diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..ead13f9
Binary files /dev/null and b/.DS_Store differ
diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml
new file mode 100644
index 0000000..142a0bf
--- /dev/null
+++ b/.idea/assetWizardSettings.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
new file mode 100644
index 0000000..90ec770
Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..61a9130
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..c83a369
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..1c811b6
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..0dd4b35
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/markdown-navigator-enh.xml b/.idea/markdown-navigator-enh.xml
new file mode 100644
index 0000000..a8fcc84
--- /dev/null
+++ b/.idea/markdown-navigator-enh.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/markdown-navigator.xml b/.idea/markdown-navigator.xml
new file mode 100644
index 0000000..a2fc086
--- /dev/null
+++ b/.idea/markdown-navigator.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index fee3a84..635999d 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -24,7 +24,7 @@
-
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 44902a2..a0cc384 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,8 +2,8 @@
-
-
+
+
\ 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/README.md b/README.md
index 3a4466a..34ee8e0 100644
--- a/README.md
+++ b/README.md
@@ -1,72 +1,54 @@
-# ZomatoBuddy
+# Hungry
-This is a restaurant search engine by using the **Zomato API**. It displays the information based on the current geolocation of the user and then displays the list of 20 restaurants based on 3 categories, (1) Dine-out, (2) Delivery and (3) Takeaway.
-
-> Note: I took the existing Zomato application as an inspiration and a baseline to create this application. I am in no way connected to the actual application or anything related to it. The objective of the application is to use Zomato API and create a friendly application that can display those information, hence the name ZomatoBuddy.
-
-The Zomato API needs to be defined in the gradle.properties file. You can also modify the default location to use incase the user did not provide the permission for the geolocation.
-
-This application has been deployed into Google Play Store:
-https://play.google.com/store/apps/details?id=com.soumya.wwdablu.zomatobuddy&hl=en
-
-> The master branch contains the latest working code, but may or may not be the one that is present in the Play Store. Check the branches with the current date. Branches marked with the most current date is the one that is present in Play Store.
+Upgrading the application to Kotlin and matching the UI as of Zomato release in Dec, 2020
+This is still a WIP version and hence on a separate branch.
+**__Libraries used during development:__**
+* Recycler View
+* Card View
+* Retrofit
+* RxJava
+* Glide
+* Hilt
+* Room
+* Timber
-**__Information__**
+**__Asset Credits:__**
-* Top 20 restaurants
- This displays the list of 20 restaurants in the location in three categories. We can click on them to dislay their results.
-* Restaurant Images
- The images are not provided by the Zomato API for the basic version. For this reason , we are using sample images based on the first cuisine mentioned (this is being returned by the Zomato API). Also for the menu and photos, we are using the URL which is returned by the API. Hence to view the actual images, the user needs to visit the URLs provided in the details page.
-
-* Search Feature
- This perform the search feature based on the query provided by the user. It uses the approach to wait for the user to complete the query and then peform the Search Network API. This can be achieved by using the debounce method in conjunction with the SearchView query change listener. The query change listeners fires all the time, but the actual method of execution will only be called (which will return an observable) once the debounce timeout has been completed, uninterupted. This makes it more flowing with the user and removes the requirement for a search button (which would then require another click action).
-
-* Favourite Restaurant
- A restaurant can be marked/unmarked as a favourite. It will be displayed in a separate tab inside the application. Realm database has been used to perform the local storage functionality.
-
-* Analytics
- Using Firebase Analytics to log events like which screen is displayed to the user and the search terms used.
+This project contains various assets which are owed by the respective owners.
+Their details are provided as below
-**__Libraries used during development:__**
+* Icons made by Freepik from www.flaticon.com
+Facebook, Google, Delivery, Catchup, Dinner, Cafe, Buffet
-* Recycler View
-* Card View
-* Design Library
- * NestedScrollView
- * CollapsingToolbarLayout
- * FragmentStatePageAdapter
- * ViewPager
- * CoordinatorLayout
-* Fused Location Provider (Google Play services - Location)
-* Retrofit
-* RxJava
-* Firebase Analytics
-* Picasso
-* Dagger 2
-* Parceler
-* Realm
-* Timber
+* Location vector created by stories - www.freepik.com
+Search Location
+* Icons made by Eucalyp from www.flaticon.com
+Dining, Lunch
-**__Screenshot__**
+* Icons made by Kiranshastry from www.flaticon.com
+Nightlife
-![Screenshot](/screenshot/ZB_Usage_12_02.gif?raw=true "Sample")
+* Icons made by Pixel perfect from www.flaticon.com
+Profile
-> The GIF may or may not updated. This is just for reference. Download the actual code and try it.
+* Pattern vector created by freepik - www.freepik.com
+Default background image for cards
+* Icons made by Good Ware from www.flaticon.com
+Takeout
+* Icons made by Pixelmeetup from www.flaticon.com
+Breakfast
-**__Changelog__**
+* Icons made by surang from www.flaticon.com
+Club
-08 - Ability to mark restaurants as favourite. UI fixes.
-07 - Added Firebase Analytics (current screen and log event - search term)
-06 - Added share feature with UI tweaks. Added powered by Zomato text to show API usage.
-05 - Lint and defect fixes
-04 - Addition of reviews
-03 - Addition of search feature
-02 - Addition of details screen
-01 - Initial checkin
+* Food vector created by stories - www.freepik.com
+Image of chef in login screen
+* https://lottiefiles.com/968-loading
+Loading Lottie - 1
diff --git a/app/.DS_Store b/app/.DS_Store
new file mode 100644
index 0000000..d8ee98f
Binary files /dev/null and b/app/.DS_Store differ
diff --git a/app/build.gradle b/app/build.gradle
index 94bc1b7..f105305 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,15 +1,17 @@
apply plugin: 'com.android.application'
-apply plugin: 'realm-android'
-
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
+apply plugin: 'kotlin-parcelize'
+apply plugin: 'dagger.hilt.android.plugin'
android {
- compileSdkVersion 26
+ compileSdkVersion 29
defaultConfig {
- applicationId "com.soumya.wwdablu.zomatobuddy"
- minSdkVersion 19
- targetSdkVersion 26
- versionCode 4
- versionName "1.1.2"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ applicationId "com.soumya.wwdablu.hungry"
+ minSdkVersion 26
+ targetSdkVersion 29
+ versionCode 6
+ versionName "3.0.0"
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
@@ -18,11 +20,12 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
- dataBinding {
- enabled true
+ buildFeatures {
+ dataBinding true
+ viewBinding true
}
buildTypes.each {
- it.buildConfigField("String", "ZOMATO_API_KEY", ZOMATO_API)
+ it.buildConfigField("String", "ZOMATO_API_KEY", ZOMATO_API_KEY)
it.buildConfigField("String", "ZOMATO_BASE_URL", ZOMATO_BASE_URL)
it.buildConfigField("String", "DEFAULT_LOGITUDE", DEFAULT_LONGITUDE)
it.buildConfigField("String", "DEFAULT_LATITUDE", DEFAULT_LATITUDE)
@@ -31,49 +34,55 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:26.1.0'
- implementation 'com.android.support:recyclerview-v7:26.1.0'
- implementation 'com.android.support.constraint:constraint-layout:1.0.2'
- implementation 'com.android.support:design:26.1.0'
- implementation 'com.android.support:cardview-v7:26.1.0'
- implementation 'com.android.support:support-v4:26.1.0'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation 'com.google.android.material:material:1.2.1'
+ implementation 'androidx.cardview:cardview:1.0.0'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation "androidx.viewpager2:viewpager2:1.0.0"
+ implementation 'androidx.paging:paging-runtime-ktx:2.1.2'
+ implementation 'androidx.core:core-ktx:1.3.2'
- implementation 'com.google.android.gms:play-services-location:11.6.2'
+ implementation 'com.google.android.gms:play-services-location:17.1.0'
- implementation 'com.google.firebase:firebase-core:11.6.2'
+ implementation "androidx.room:room-runtime:2.2.6"
+ kapt "androidx.room:room-compiler:2.2.6"
- implementation 'com.squareup.retrofit2:retrofit:2.3.0'
+ implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
- implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
- implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
+ implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
- implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
- implementation 'io.reactivex.rxjava2:rxjava:2.1.5'
+ implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
+ implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
- implementation 'com.google.dagger:dagger:2.12'
- annotationProcessor 'com.google.dagger:dagger-compiler:2.12'
+ implementation "com.google.dagger:hilt-android:2.28-alpha"
+ kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
- implementation 'com.squareup.picasso:picasso:2.5.2'
+ implementation 'com.airbnb.android:lottie:3.5.0'
- implementation 'org.parceler:parceler-api:1.1.9'
- annotationProcessor 'org.parceler:parceler:1.1.9'
+ //Glide - Image handling
+ implementation 'com.github.bumptech.glide:glide:4.11.0'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
- implementation 'com.jakewharton.timber:timber:4.6.0'
+ //Timber - Logging
+ implementation 'com.jakewharton.timber:timber:4.7.1'
- debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
- releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
+ //Phone input field with flag and country code
+ implementation 'com.github.wwdablu:PhoneInputExt:1.0.0'
testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.1'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
-}
-
-
-apply plugin: 'com.google.gms.google-services'
\ No newline at end of file
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
\ No newline at end of file
diff --git a/app/src/.DS_Store b/app/src/.DS_Store
new file mode 100644
index 0000000..dde004c
Binary files /dev/null and b/app/src/.DS_Store differ
diff --git a/app/src/androidTest/java/com/soumya/wwdablu/hungry/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/soumya/wwdablu/hungry/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..3066715
--- /dev/null
+++ b/app/src/androidTest/java/com/soumya/wwdablu/hungry/ExampleInstrumentedTest.kt
@@ -0,0 +1,23 @@
+package com.soumya.wwdablu.hungry
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see [Testing documentation](http://d.android.com/tools/testing)
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ @Throws(Exception::class)
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ Assert.assertEquals("com.soumya.wwdablu.hungry", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/soumya/wwdablu/zomatobuddy/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/soumya/wwdablu/zomatobuddy/ExampleInstrumentedTest.java
deleted file mode 100644
index 4fc2562..0000000
--- a/app/src/androidTest/java/com/soumya/wwdablu/zomatobuddy/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy;
-
-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.*;
-
-/**
- * Instrumented 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.soumya.wwdablu.zomatobuddy", appContext.getPackageName());
- }
-}
diff --git a/app/src/debug/.DS_Store b/app/src/debug/.DS_Store
new file mode 100644
index 0000000..2dd38d3
Binary files /dev/null and b/app/src/debug/.DS_Store differ
diff --git a/app/src/debug/java/.DS_Store b/app/src/debug/java/.DS_Store
new file mode 100644
index 0000000..d886c99
Binary files /dev/null and b/app/src/debug/java/.DS_Store differ
diff --git a/app/src/debug/java/com/.DS_Store b/app/src/debug/java/com/.DS_Store
new file mode 100644
index 0000000..52d9e32
Binary files /dev/null and b/app/src/debug/java/com/.DS_Store differ
diff --git a/app/src/debug/java/com/soumya/.DS_Store b/app/src/debug/java/com/soumya/.DS_Store
new file mode 100644
index 0000000..0c3b07b
Binary files /dev/null and b/app/src/debug/java/com/soumya/.DS_Store differ
diff --git a/app/src/debug/java/com/soumya/wwdablu/.DS_Store b/app/src/debug/java/com/soumya/wwdablu/.DS_Store
new file mode 100644
index 0000000..687d495
Binary files /dev/null and b/app/src/debug/java/com/soumya/wwdablu/.DS_Store differ
diff --git a/app/src/debug/java/com/soumya/wwdablu/hungry/HungryApplication.kt b/app/src/debug/java/com/soumya/wwdablu/hungry/HungryApplication.kt
new file mode 100644
index 0000000..8ebfbc5
--- /dev/null
+++ b/app/src/debug/java/com/soumya/wwdablu/hungry/HungryApplication.kt
@@ -0,0 +1,14 @@
+package com.soumya.wwdablu.hungry
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+import timber.log.Timber
+
+@HiltAndroidApp
+class HungryApplication : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ //Init debug version of Timber tree
+ Timber.plant(HungryDebugTree())
+ }
+}
\ No newline at end of file
diff --git a/app/src/debug/java/com/soumya/wwdablu/hungry/HungryDebugTree.kt b/app/src/debug/java/com/soumya/wwdablu/hungry/HungryDebugTree.kt
new file mode 100644
index 0000000..88a1caa
--- /dev/null
+++ b/app/src/debug/java/com/soumya/wwdablu/hungry/HungryDebugTree.kt
@@ -0,0 +1,9 @@
+package com.soumya.wwdablu.hungry
+
+import timber.log.Timber.DebugTree
+
+class HungryDebugTree : DebugTree() {
+ override fun createStackElementTag(element: StackTraceElement): String {
+ return super.createStackElementTag(element) + "[" + element.lineNumber + "]"
+ }
+}
\ No newline at end of file
diff --git a/app/src/debug/java/com/soumya/wwdablu/zomatobuddy/BuddyDebugTree.java b/app/src/debug/java/com/soumya/wwdablu/zomatobuddy/BuddyDebugTree.java
deleted file mode 100644
index d616d95..0000000
--- a/app/src/debug/java/com/soumya/wwdablu/zomatobuddy/BuddyDebugTree.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy;
-
-import timber.log.Timber;
-
-public class BuddyDebugTree extends Timber.DebugTree {
-
- @Override
- protected String createStackElementTag(StackTraceElement element) {
- return super.createStackElementTag(element) + "[" + element.getLineNumber() + "]";
- }
-}
diff --git a/app/src/debug/java/com/soumya/wwdablu/zomatobuddy/ZomatoBuddyApplication.java b/app/src/debug/java/com/soumya/wwdablu/zomatobuddy/ZomatoBuddyApplication.java
deleted file mode 100644
index 0bbbb29..0000000
--- a/app/src/debug/java/com/soumya/wwdablu/zomatobuddy/ZomatoBuddyApplication.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy;
-
-import android.app.Application;
-
-import com.soumya.wwdablu.zomatobuddy.common.Analytics;
-import com.soumya.wwdablu.zomatobuddy.database.CacheDB;
-import com.squareup.leakcanary.LeakCanary;
-
-import io.realm.Realm;
-import timber.log.Timber;
-
-public class ZomatoBuddyApplication extends Application {
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- if (LeakCanary.isInAnalyzerProcess(this)) {
- return;
- }
- LeakCanary.install(this);
-
- //Init the CacheDB
- CacheDB.init(this);
-
- //Init analytics
- Analytics.init(this);
-
- //Realm init
- Realm.init(this);
-
- //Init debug version of Timber tree
- Timber.plant(new BuddyDebugTree());
- }
-}
diff --git a/app/src/main/.DS_Store b/app/src/main/.DS_Store
new file mode 100644
index 0000000..ddf16f4
Binary files /dev/null and b/app/src/main/.DS_Store differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f32ea31..d38b537 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,35 +1,63 @@
+ package="com.soumya.wwdablu.hungry">
+
+ android:name=".activity.SearchActivity"
+ android:theme="@style/AppTheme.NoActionBar"
+ android:launchMode="singleTask"
+ android:exported="false" />
+
+
+
+
+
+
+
+
-
-
-
\ No newline at end of file
diff --git a/app/src/main/assets/lottie_loading.json b/app/src/main/assets/lottie_loading.json
new file mode 100644
index 0000000..92302e6
--- /dev/null
+++ b/app/src/main/assets/lottie_loading.json
@@ -0,0 +1 @@
+{"v":"4.12.0","fr":15,"ip":0,"op":90,"w":200,"h":200,"nm":"loading","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"loading Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,103.5,0],"ix":2},"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.246,0],[0,-5.247],[-5.247,0],[0,5.247]],"o":[[-5.247,0],[0,5.247],[5.246,0],[0,-5.247]],"v":[[0,-9.5],[-9.5,0],[0,9.5],[9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-4.687,0],[0,-4.687],[4.687,0],[0,4.687]],"o":[[4.687,0],[0,4.687],[-4.687,0],[0,-4.687]],"v":[[0,-8.5],[8.5,0],[0,8.5],[-8.5,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":64,"s":[0],"e":[100]},{"t":79}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"fl","c":{"a":0,"k":[0.8862745098039215,0.21568627450980393,0.26666666666666666,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[165.792,93.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":61,"s":[0,0],"e":[150,150]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":76,"s":[150,150],"e":[100,100]},{"t":81}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"6","np":5,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.247,0],[0,-5.247],[-5.247,0],[0,5.247]],"o":[[-5.247,0],[0,5.247],[5.247,0],[0,-5.247]],"v":[[0,-9.5],[-9.5,0],[0,9.5],[9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-4.687,0],[0,-4.687],[4.687,0],[0,4.687]],"o":[[4.687,0],[0,4.687],[-4.687,0],[0,-4.687]],"v":[[0,-8.5],[8.5,0],[0,8.5],[-8.5,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":49,"s":[0],"e":[100]},{"t":64}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"fl","c":{"a":0,"k":[0.8862745098039215,0.21568627450980393,0.26666666666666666,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[138.875,93.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":46,"s":[0,0],"e":[150,150]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":61,"s":[150,150],"e":[100,100]},{"t":67}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"5","np":5,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.247,0],[0,-5.247],[-5.246,0],[0,5.247]],"o":[[-5.246,0],[0,5.247],[5.247,0],[0,-5.247]],"v":[[0,-9.5],[-9.5,0],[0,9.5],[9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-4.687,0],[0,-4.687],[4.687,0],[0,4.687]],"o":[[4.687,0],[0,4.687],[-4.687,0],[0,-4.687]],"v":[[0,-8.5],[8.5,0],[0,8.5],[-8.5,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":34,"s":[0],"e":[100]},{"t":49}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"fl","c":{"a":0,"k":[0.8862745098039215,0.21568627450980393,0.26666666666666666,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[111.958,93.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":31,"s":[0,0],"e":[150,150]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":45,"s":[150,150],"e":[100,100]},{"t":51}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"4","np":5,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.247,0],[0,-5.247],[-5.247,0],[0,5.247]],"o":[[-5.247,0],[0,5.247],[5.247,0],[0,-5.247]],"v":[[0,-9.5],[-9.5,0],[0,9.5],[9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-4.687,0],[0,-4.687],[4.687,0],[0,4.687]],"o":[[4.687,0],[0,4.687],[-4.687,0],[0,-4.687]],"v":[[0,-8.5],[8.5,0],[0,8.5],[-8.5,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":21,"s":[0],"e":[100]},{"t":36}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"fl","c":{"a":0,"k":[0.8862745098039215,0.21568627450980393,0.26666666666666666,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[85.041,93.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":19,"s":[100,100],"e":[150,150]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":34,"s":[150,150],"e":[100,100]},{"t":39}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"3","np":5,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.247,0],[0,-5.247],[-5.247,0],[0,5.247]],"o":[[-5.247,0],[0,5.247],[5.247,0],[0,-5.247]],"v":[[0,-9.5],[-9.5,0],[0,9.5],[9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-4.687,0],[0,-4.687],[4.687,0],[0,4.687]],"o":[[4.687,0],[0,4.687],[-4.687,0],[0,-4.687]],"v":[[0,-8.5],[8.5,0],[0,8.5],[-8.5,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":12,"s":[0],"e":[100]},{"t":27}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"fl","c":{"a":0,"k":[0.8862745098039215,0.21568627450980393,0.26666666666666666,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[58.125,93.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":10,"s":[0,0],"e":[150,150]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":25,"s":[150,150],"e":[100,100]},{"t":30}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"2","np":5,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.247,0],[0,-5.247],[-5.247,0],[0,5.247]],"o":[[-5.247,0],[0,5.247],[5.247,0],[0,-5.247]],"v":[[0,-9.5],[-9.5,0],[0,9.5],[9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-4.687,0],[0,-4.687],[4.687,0],[0,4.687]],"o":[[4.687,0],[0,4.687],[-4.687,0],[0,-4.687]],"v":[[0,-8.5],[8.5,0],[0,8.5],[-8.5,0]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":3,"s":[0],"e":[100]},{"t":18}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":4,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"fl","c":{"a":0,"k":[0.8862745098039215,0.21568627450980393,0.26666666666666666,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[31.208,93.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[0,0],"e":[150,150]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":15,"s":[150,150],"e":[100,100]},{"t":20}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"1","np":5,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":90,"st":0,"bm":0}]}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/CollectionDetailsActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/CollectionDetailsActivity.kt
new file mode 100644
index 0000000..810a52e
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/CollectionDetailsActivity.kt
@@ -0,0 +1,86 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.content.Intent
+import android.os.Bundle
+import android.os.Parcelable
+import android.view.View
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.soumya.wwdablu.hungry.databinding.ActivityCollectionDetailsBinding
+import com.soumya.wwdablu.hungry.iface.RestaurantItemSelector
+import com.soumya.wwdablu.hungry.adapter.GenericSearchResultAdapter
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionInfo
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import timber.log.Timber
+
+class CollectionDetailsActivity : HungryActivity() {
+
+ private lateinit var mViewBinding: ActivityCollectionDetailsBinding
+ private lateinit var mSearchModel: SearchModel
+ private lateinit var mAdapter: GenericSearchResultAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivityCollectionDetailsBinding.inflate(layoutInflater)
+
+ mViewBinding.rvResByCollection.layoutManager = LinearLayoutManager(this)
+ getRestaurantsByCollectionId(intent.getStringExtra("collection_id") ?: "1")
+
+ val collectionInfoParcelable: Parcelable? = intent.getParcelableExtra("collection_info")
+ if(collectionInfoParcelable != null) {
+ val model: CollectionInfo = collectionInfoParcelable as CollectionInfo
+ mViewBinding.collectionModel = model
+ loadImageIntoImageView(model.imageUrl, mViewBinding.ivRestaurantImage)
+ }
+
+ setContentView(mViewBinding.root)
+ }
+
+ private fun getRestaurantsByCollectionId(collectionId: String) {
+
+ HungryRepo.searchByCollectionId(collectionId.toInt())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver() {
+ override fun onNext(t: SearchModel?) {
+
+ if(t != null) {
+ mSearchModel = t
+ }
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ finish()
+ }
+
+ override fun onComplete() {
+
+ if(this@CollectionDetailsActivity::mSearchModel.isInitialized &&
+ !this@CollectionDetailsActivity::mAdapter.isInitialized) {
+ mAdapter = GenericSearchResultAdapter(mSearchModel, mListener)
+ mViewBinding.rvResByCollection.adapter = mAdapter
+
+ mViewBinding.lotLoading.cancelAnimation()
+ mViewBinding.lotLoading.visibility = View.GONE
+ mViewBinding.rvResByCollection.visibility = View.VISIBLE
+ }
+ }
+ })
+ }
+
+ private val mListener = object: RestaurantItemSelector {
+ override fun onRestaurantClicked(restaurant: RestaurantInfo) {
+ runOnUiThread {
+ val intent: Intent = Intent(this@CollectionDetailsActivity, RestaurantDetailsActivity::class.java)
+ intent.putExtra("res_details", restaurant)
+ startActivity(intent)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/CollectionsActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/CollectionsActivity.kt
new file mode 100644
index 0000000..a69399c
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/CollectionsActivity.kt
@@ -0,0 +1,72 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.soumya.wwdablu.hungry.adapter.CollectionsAdapter
+import com.soumya.wwdablu.hungry.databinding.ActivityCollectionsBinding
+import com.soumya.wwdablu.hungry.iface.CollectionItemSelector
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionInfo
+import com.soumya.wwdablu.hungry.network.model.collections.CuratedCollection
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import timber.log.Timber
+
+class CollectionsActivity : HungryActivity(), CollectionItemSelector {
+
+ private lateinit var mAdapter: CollectionsAdapter
+ private lateinit var mViewBinding: ActivityCollectionsBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivityCollectionsBinding.inflate(layoutInflater)
+
+ mViewBinding.rvCollections.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
+ getCollection()
+
+ setContentView(mViewBinding.root)
+ }
+
+ private fun getCollection() {
+
+ HungryRepo.getCollections()
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver>() {
+ override fun onNext(t: List?) {
+
+ if(t != null) {
+ mAdapter = CollectionsAdapter(t, this@CollectionsActivity)
+ }
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ finish()
+ }
+
+ override fun onComplete() {
+
+ if(this@CollectionsActivity::mAdapter.isInitialized) {
+ mViewBinding.lotLoading.cancelAnimation()
+ mViewBinding.lotLoading.visibility = View.GONE
+ mViewBinding.rvCollections.visibility = View.VISIBLE
+ mViewBinding.rvCollections.adapter = mAdapter
+ }
+ }
+ })
+ }
+
+ override fun onCollectionClicked(collection: CollectionInfo) {
+ runOnUiThread {
+ val intent: Intent = Intent(this, CollectionDetailsActivity::class.java)
+ intent.putExtra("collection_id", collection.id)
+ intent.putExtra("collection_info", collection)
+ startActivity(intent)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/DashboardActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/DashboardActivity.kt
new file mode 100644
index 0000000..1114db4
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/DashboardActivity.kt
@@ -0,0 +1,76 @@
+package com.soumya.wwdablu.hungry.activity
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.customview.DashboardBottomNaviView
+import com.soumya.wwdablu.hungry.databinding.ActivityDashboardBinding
+import com.soumya.wwdablu.hungry.defines.CategoryEnum
+import com.soumya.wwdablu.hungry.defines.SearchBy
+import com.soumya.wwdablu.hungry.fragment.RecommendedFragment
+import com.soumya.wwdablu.hungry.fragment.GenericSearchResultFragment
+import com.soumya.wwdablu.hungry.fragment.ProfileFragment
+import java.util.*
+
+class DashboardActivity : AppCompatActivity() {
+
+ private lateinit var mViewBinding: ActivityDashboardBinding
+
+ private val mCategoryFragmentMap: EnumMap = EnumMap(CategoryEnum::class.java)
+ private lateinit var mRecommendedFragment: RecommendedFragment
+ private lateinit var mProfileFragment: ProfileFragment
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivityDashboardBinding.inflate(layoutInflater)
+
+ mViewBinding.bnvBottomMenu.setOnNavigationItemSelectedListener(navigationItemClickListener)
+
+ setContentView(mViewBinding.root)
+ }
+
+ private val navigationItemClickListener: BottomNavigationView.OnNavigationItemSelectedListener
+ = BottomNavigationView.OnNavigationItemSelectedListener {
+
+ when (it.itemId) {
+ CategoryEnum.Recommended.ordinal -> {
+
+ if(!this::mRecommendedFragment.isInitialized) {
+ mRecommendedFragment = RecommendedFragment.newInstance()
+ }
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.fl_frag_container, mRecommendedFragment, RecommendedFragment::class.java.simpleName)
+ .commitAllowingStateLoss()
+ }
+
+ DashboardBottomNaviView.ProfileMenu -> {
+
+ if(!this::mProfileFragment.isInitialized) {
+ mProfileFragment = ProfileFragment.newInstance()
+ }
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.fl_frag_container, mProfileFragment, ProfileFragment::class.java.simpleName)
+ .commitAllowingStateLoss()
+ }
+
+ else -> {
+
+ val catEnum: CategoryEnum = CategoryEnum.values()[it.itemId-1]
+ var catFrag: Fragment? = mCategoryFragmentMap[catEnum]
+ if(catFrag == null) {
+ catFrag = GenericSearchResultFragment.newInstance(SearchBy.Category, catEnum.name,
+ SearchBy.Collection, "1")
+ mCategoryFragmentMap[catEnum] = catFrag
+ }
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.fl_frag_container, catFrag, GenericSearchResultFragment::class.java.simpleName)
+ .commitAllowingStateLoss()
+ }
+ }
+
+ return@OnNavigationItemSelectedListener true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/GenericSearchResultActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/GenericSearchResultActivity.kt
new file mode 100644
index 0000000..c343898
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/GenericSearchResultActivity.kt
@@ -0,0 +1,61 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.defines.SearchBy
+import com.soumya.wwdablu.hungry.fragment.GenericSearchResultFragment
+
+class GenericSearchResultActivity : HungryActivity() {
+
+ companion object {
+ fun createLaunchIntent(context: Context, primarySearch: SearchBy, primarySearchParam: String,
+ fallbackSearch: SearchBy = SearchBy.None, fallbackSearchParam: String = "") : Intent {
+
+ val intent = Intent(context, GenericSearchResultActivity::class.java)
+
+ val bundle = Bundle()
+ bundle.putSerializable("key.primary_search", primarySearch)
+ bundle.putString("key.primary_search_param", primarySearchParam)
+ bundle.putSerializable("key.fallback_search", fallbackSearch)
+ bundle.putString("key.fallback_search_param", fallbackSearchParam)
+
+ intent.putExtras(bundle)
+ return intent
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_generic_search_result)
+
+ val bundle: Bundle? = intent.extras
+ if(bundle == null) {
+ finish()
+ return
+ }
+
+ val fragment = GenericSearchResultFragment.newInstance(
+ bundle.getSerializable("key.primary_search") as SearchBy,
+ bundle.getString("key.primary_search_param", ""),
+ bundle.getSerializable("key.fallback_search") as SearchBy,
+ bundle.getString("key.fallback_search_param", "")
+ )
+
+ supportFragmentManager.beginTransaction()
+ .add(R.id.fl_frag_container, fragment, GenericSearchResultFragment::class.java.simpleName)
+ .addToBackStack(GenericSearchResultFragment::class.java.simpleName)
+ .commitAllowingStateLoss()
+ }
+
+ override fun onBackPressed() {
+
+ if(supportFragmentManager.backStackEntryCount == 1) {
+ finish()
+ return
+ }
+
+ super.onBackPressed()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/HungryActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/HungryActivity.kt
new file mode 100644
index 0000000..5029846
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/HungryActivity.kt
@@ -0,0 +1,124 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.pm.PackageManager
+import android.location.Criteria
+import android.location.Location
+import android.location.LocationListener
+import android.location.LocationManager
+import android.os.Bundle
+import android.os.Handler
+import android.view.inputmethod.InputMethodManager
+import android.widget.ImageView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import com.bumptech.glide.Glide
+import com.soumya.wwdablu.hungry.BuildConfig
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+
+abstract class HungryActivity : AppCompatActivity(), LocationListener {
+
+ private var mLat: String = BuildConfig.DEFAULT_LATITUDE
+ private var mLon: String = BuildConfig.DEFAULT_LOGITUDE
+
+ private val mHandler: Handler = Handler()
+
+ fun hideKeyboard() {
+ val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ inputMethodManager.hideSoftInputFromWindow(currentFocus?.windowToken, 0)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ val locationManager: LocationManager? = getSystemService(Context.LOCATION_SERVICE) as LocationManager?
+ locationManager?.removeUpdates(this)
+ }
+
+ @SuppressLint("MissingPermission")
+ override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
+
+ if(requestCode == 1001) {
+ if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+
+ val locationManager: LocationManager? = getSystemService(Context.LOCATION_SERVICE) as LocationManager?
+ locationManager?.requestLocationUpdates(
+ locationManager.getBestProvider(Criteria(), false) ?:
+ LocationManager.GPS_PROVIDER,
+ 500, 1.0f, this)
+ }
+
+ return
+ }
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ }
+
+ override fun onLocationChanged(location: Location?) {
+ val locationManager: LocationManager? = getSystemService(Context.LOCATION_SERVICE) as LocationManager?
+ locationManager?.removeUpdates(this)
+
+ mLat = location?.latitude?.toString() ?: BuildConfig.DEFAULT_LATITUDE
+ mLon = location?.longitude?.toString() ?: BuildConfig.DEFAULT_LOGITUDE
+
+ HungryRepo.setLocation(mLat, mLon)
+
+ onLocationUpdated(location)
+ }
+
+ override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
+ //
+ }
+
+ override fun onProviderEnabled(provider: String?) {
+ //
+ }
+
+ override fun onProviderDisabled(provider: String?) {
+ //
+ }
+
+ protected open fun onLocationUpdated(location: Location?) {
+ //
+ }
+
+ protected fun postRunnableOnMain(r: Runnable, delayInMilli: Long = 0, cancelIfExists: Boolean = false) {
+ if(cancelIfExists) {
+ mHandler.removeCallbacks(r)
+ }
+ mHandler.postDelayed(r, delayInMilli)
+ }
+
+ protected fun fetchCurrentCoordinates() {
+
+ val locationManager: LocationManager? = getSystemService(Context.LOCATION_SERVICE) as LocationManager?
+
+ if(locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER) == true) {
+ val permissionResult = ContextCompat.checkSelfPermission(this,
+ android.Manifest.permission.ACCESS_FINE_LOCATION)
+
+ when (permissionResult) {
+ PackageManager.PERMISSION_GRANTED -> {
+ locationManager.requestLocationUpdates(
+ locationManager.getBestProvider(Criteria(), false) ?:
+ LocationManager.GPS_PROVIDER,
+ 500, 1.0f, this)
+ }
+ PackageManager.PERMISSION_DENIED -> {
+ requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 1001)
+ }
+ else -> {
+ requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 1001)
+ }
+ }
+ }
+ }
+
+ protected fun loadImageIntoImageView(imageUrl: String, imageView: ImageView) {
+
+ Glide.with(imageView.context)
+ .load(imageUrl)
+ .placeholder(R.drawable.default_card_bg)
+ .into(imageView)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/LocationAccess.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/LocationAccess.kt
new file mode 100644
index 0000000..463fecc
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/LocationAccess.kt
@@ -0,0 +1,54 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.content.Intent
+import android.location.Location
+import android.os.Bundle
+import com.soumya.wwdablu.hungry.databinding.ActivityLocationAccessBinding
+import com.soumya.wwdablu.hungry.network.model.cities.City
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+
+class LocationAccess : HungryActivity() {
+
+ private lateinit var mViewBinding: ActivityLocationAccessBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivityLocationAccessBinding.inflate(layoutInflater)
+
+ mViewBinding.btnAutoLocation.setOnClickListener {
+ fetchCurrentCoordinates()
+ }
+
+ setContentView(mViewBinding.root)
+ }
+
+ override fun onLocationUpdated(location: Location?) {
+
+ HungryRepo.getCity()
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver>() {
+ override fun onNext(t: List?) {
+ //
+ }
+
+ override fun onError(e: Throwable?) {
+ //
+ }
+
+ override fun onComplete() {
+ runOnUiThread {
+ runOnUiThread {
+ startActivity(Intent(this@LocationAccess,
+ DashboardActivity::class.java))
+ finish()
+ }
+ }
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/LoginActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/LoginActivity.kt
new file mode 100644
index 0000000..79784c5
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/LoginActivity.kt
@@ -0,0 +1,79 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.content.Context
+import android.content.Intent
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import androidx.annotation.MainThread
+import com.soumya.wwdablu.hungry.database.HungryDatabase
+import com.soumya.wwdablu.hungry.database.userinfo.UserInfo
+import com.soumya.wwdablu.hungry.databinding.ActivityLoginBinding
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.core.Observable
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+
+class LoginActivity : AppCompatActivity() {
+
+ private lateinit var mViewBinding: ActivityLoginBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivityLoginBinding.inflate(layoutInflater)
+
+ mViewBinding.btnGetOtp.setOnClickListener {
+
+ val inputPhone: String = mViewBinding.piPhoneNumber.getSelectedData().second
+ if(inputPhone.isBlank() || inputPhone.isEmpty()) {
+ return@setOnClickListener
+ }
+
+ registerUser(it.context, inputPhone)
+ }
+
+ mViewBinding.btnSkip.setOnClickListener {
+ launchLocationAccessPermissionActivity(it.context)
+ }
+
+ setContentView(mViewBinding.root)
+ }
+
+ @MainThread
+ private fun launchLocationAccessPermissionActivity(context: Context) {
+ startActivity(Intent(context, LocationAccess::class.java))
+ }
+
+ private fun registerUser(context: Context, userId: String) {
+
+ Observable.create {
+ val user:UserInfo? = HungryDatabase.getDB(context).UserInfoDao().isUserRegistered(userId)
+ if(user == null) {
+ HungryDatabase.getDB(context).UserInfoDao().registerLoggedInUser(UserInfo(
+ isLoggedIn = true, userIdentifier = userId))
+ } else {
+ user.isLoggedIn = true
+ HungryDatabase.getDB(context).UserInfoDao().updateLoginStatus(user)
+ }
+
+ it.onNext(user)
+ it.onComplete()
+
+ }.observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver() {
+ override fun onNext(t: UserInfo?) {
+ //
+ }
+
+ override fun onError(e: Throwable?) {
+ //
+ }
+
+ override fun onComplete() {
+ launchLocationAccessPermissionActivity(this@LoginActivity)
+ finish()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/PhotoViewerActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/PhotoViewerActivity.kt
new file mode 100644
index 0000000..5be6af4
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/PhotoViewerActivity.kt
@@ -0,0 +1,69 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.annotation.SuppressLint
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.view.MotionEvent
+import android.view.View
+import android.widget.ImageView
+import com.bumptech.glide.Glide
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.databinding.ActivityPhotoViewerBinding
+
+class PhotoViewerActivity : AppCompatActivity() {
+
+ private lateinit var mViewBinding: ActivityPhotoViewerBinding
+ private var mList: ArrayList? = null
+ private var mIndex: Int = 0
+
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivityPhotoViewerBinding.inflate(layoutInflater)
+
+ mList = intent.getStringArrayListExtra("list")
+ mIndex = intent.getIntExtra("index", 0)
+ if(mList == null) {
+ finish()
+ return
+ }
+
+ Glide.with(mViewBinding.ivImage)
+ .load(mList!![mIndex])
+ .placeholder(R.drawable.default_card_bg)
+ .into(mViewBinding.ivImage)
+
+ mViewBinding.btnNext.setOnClickListener {
+
+ if(mIndex >= mList!!.size) {
+ it.visibility = View.GONE
+ return@setOnClickListener
+ }
+
+ Glide.with(it.context)
+ .load(mList!![mIndex])
+ .placeholder(R.drawable.default_card_bg)
+ .into(mViewBinding.ivImage)
+
+ mIndex++
+ }
+
+ mViewBinding.btnPrev.setOnClickListener {
+
+ if(mIndex < 0) {
+ it.visibility = View.GONE
+ return@setOnClickListener
+ }
+
+ mIndex--
+
+ Glide.with(it.context)
+ .load(mList!![mIndex])
+ .placeholder(R.drawable.default_card_bg)
+ .into(mViewBinding.ivImage)
+ }
+
+ setContentView(mViewBinding.root)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/RestaurantDetailsActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/RestaurantDetailsActivity.kt
new file mode 100644
index 0000000..764dbdf
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/RestaurantDetailsActivity.kt
@@ -0,0 +1,87 @@
+package com.soumya.wwdablu.hungry.activity
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.Fragment
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.soumya.wwdablu.hungry.customview.RestaurantDetailsBottomNaviView
+import com.soumya.wwdablu.hungry.databinding.ActivityRestaurantDetailsBinding
+import com.soumya.wwdablu.hungry.fragment.resdetails.OverviewFragment
+import com.soumya.wwdablu.hungry.fragment.resdetails.PhotosFragment
+import com.soumya.wwdablu.hungry.fragment.resdetails.ReviewFragment
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import java.util.*
+
+class RestaurantDetailsActivity : AppCompatActivity() {
+
+ private lateinit var mViewBinding: ActivityRestaurantDetailsBinding
+ private lateinit var mRestaurant: RestaurantInfo
+
+ private val mFragments: EnumMap = EnumMap(
+ RestaurantDetailsBottomNaviView.MenuItems::class.java)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivityRestaurantDetailsBinding.inflate(layoutInflater)
+
+ mViewBinding.bnvBottomMenu.setOnNavigationItemSelectedListener(navigationItemClickListener)
+ mViewBinding.bnvBottomMenu.visibility = View.GONE
+
+ val resInfo: RestaurantInfo? = intent.getParcelableExtra("res_details")
+
+ if(resInfo != null) {
+
+ mRestaurant = resInfo
+
+ mViewBinding.bnvBottomMenu.visibility = View.VISIBLE
+ mViewBinding.bnvBottomMenu.selectedItemId = RestaurantDetailsBottomNaviView
+ .MenuItems.Overview.ordinal
+
+ setContentView(mViewBinding.root)
+ } else {
+ finish()
+ }
+ }
+
+ private val navigationItemClickListener: BottomNavigationView.OnNavigationItemSelectedListener
+ = BottomNavigationView.OnNavigationItemSelectedListener {
+
+ if(!this::mRestaurant.isInitialized) {
+ return@OnNavigationItemSelectedListener true
+ }
+
+ val menuItem: RestaurantDetailsBottomNaviView.MenuItems = RestaurantDetailsBottomNaviView.MenuItems
+ .values()[it.itemId]
+
+ val useFragment: Fragment = when (menuItem) {
+
+ RestaurantDetailsBottomNaviView.MenuItems.Overview -> {
+ mFragments[menuItem] ?: OverviewFragment.newInstance(mRestaurant)
+ }
+
+ RestaurantDetailsBottomNaviView.MenuItems.Menu -> {
+ mFragments[menuItem] ?: PhotosFragment.newInstance(mRestaurant)
+ }
+
+ RestaurantDetailsBottomNaviView.MenuItems.Photos -> {
+ mFragments[menuItem] ?: PhotosFragment.newInstance(mRestaurant)
+ }
+
+ RestaurantDetailsBottomNaviView.MenuItems.Reviews -> {
+ mFragments[menuItem] ?: ReviewFragment.newInstance(mRestaurant)
+ }
+ }
+
+ if(!mFragments.containsKey(menuItem)) {
+ mFragments[menuItem] = useFragment
+ }
+
+ supportFragmentManager.beginTransaction()
+ .replace(mViewBinding.flFragContainer.id, useFragment, useFragment::class.java.simpleName)
+ .commitAllowingStateLoss()
+
+ return@OnNavigationItemSelectedListener true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/SearchActivity.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/SearchActivity.kt
new file mode 100644
index 0000000..3c4398f
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/SearchActivity.kt
@@ -0,0 +1,125 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.KeyEvent
+import android.widget.TextView
+import androidx.core.widget.doAfterTextChanged
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.soumya.wwdablu.hungry.adapter.SearchAdapter
+import com.soumya.wwdablu.hungry.databinding.ActivitySearchBinding
+import com.soumya.wwdablu.hungry.defines.SearchBy
+import com.soumya.wwdablu.hungry.iface.CuisineItemSelector
+import com.soumya.wwdablu.hungry.iface.RestaurantItemSelector
+import com.soumya.wwdablu.hungry.network.model.cuisine.Cuisine
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import java.util.*
+
+class SearchActivity : HungryActivity(), RestaurantItemSelector, CuisineItemSelector {
+
+ private lateinit var mViewBinding: ActivitySearchBinding
+ private lateinit var mAdapter: SearchAdapter
+
+ private var mCuisineList: LinkedList = LinkedList()
+ private var mSearchModel: SearchModel? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewBinding = ActivitySearchBinding.inflate(layoutInflater)
+
+ mViewBinding.rvSearchResults.layoutManager = LinearLayoutManager(this)
+
+ mViewBinding.etSearch.setOnEditorActionListener(mActionListener)
+ mViewBinding.etSearch.doAfterTextChanged {
+ postRunnableOnMain(mSearchRunnable, 500, true)
+ }
+ hideKeyboard()
+
+ setContentView(mViewBinding.root)
+ }
+
+ private fun search(content: String) {
+
+ if(content.isBlank() || content.isEmpty()) {
+ mCuisineList.clear()
+ mSearchModel = null
+ updateSearchAdapter()
+ return
+ }
+
+ HungryRepo.getCuisine().flatMap {
+ mCuisineList.clear()
+ mCuisineList.addAll(it.filter { me ->
+ me.cuisineName.contains(content)
+ })
+ HungryRepo.search(content)
+ }.observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver() {
+ override fun onNext(t: SearchModel?) {
+ mSearchModel = t
+ }
+
+ override fun onError(e: Throwable?) {
+ //
+ }
+
+ override fun onComplete() {
+ updateSearchAdapter()
+ }
+ })
+ }
+
+ private fun updateSearchAdapter() {
+ if(!this@SearchActivity::mAdapter.isInitialized) {
+ mAdapter = SearchAdapter(mCuisineList, mSearchModel ?:
+ SearchModel(0, 0, 0, LinkedList()),
+ this@SearchActivity, this@SearchActivity)
+
+ mViewBinding.rvSearchResults.adapter = mAdapter
+ } else {
+ mAdapter.setSearchResults(mCuisineList, mSearchModel)
+ }
+ }
+
+ private val mSearchRunnable: Runnable = Runnable {
+ search(mViewBinding.etSearch.text.toString())
+ }
+
+ private val mActionListener: TextView.OnEditorActionListener = object: TextView.OnEditorActionListener {
+ override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
+
+ hideKeyboard()
+
+ val content: String = mViewBinding.etSearch.text.toString()
+ if(content.isEmpty() || content.isBlank()) {
+ return true
+ }
+
+ search(content)
+ return true
+ }
+ }
+
+ override fun onRestaurantClicked(restaurant: RestaurantInfo) {
+ runOnUiThread {
+ val intent: Intent = Intent(this@SearchActivity, RestaurantDetailsActivity::class.java)
+ intent.putExtra("res_details", restaurant)
+ startActivity(intent)
+ }
+ }
+
+ override fun onCuisineClicked(cuisine: Cuisine) {
+ runOnUiThread {
+ val intent: Intent = GenericSearchResultActivity.createLaunchIntent(this@SearchActivity,
+ SearchBy.Cuisine, cuisine.cuisineId)
+ startActivity(intent)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/activity/SplashScreen.kt b/app/src/main/java/com/soumya/wwdablu/hungry/activity/SplashScreen.kt
new file mode 100644
index 0000000..244f3ac
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/activity/SplashScreen.kt
@@ -0,0 +1,62 @@
+package com.soumya.wwdablu.hungry.activity
+
+import android.content.Intent
+import android.location.Location
+import android.os.Bundle
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.database.HungryDatabase
+import com.soumya.wwdablu.hungry.database.userinfo.UserInfo
+import com.soumya.wwdablu.hungry.network.model.cities.City
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+
+class SplashScreen : HungryActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_splash_screen)
+
+ Thread{
+ proceed()
+ }.start()
+ }
+
+ override fun onLocationUpdated(location: Location?) {
+ HungryRepo.getCity()
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver>() {
+ override fun onNext(t: List?) {
+ //
+ }
+
+ override fun onError(e: Throwable?) {
+ //
+ }
+
+ override fun onComplete() {
+ runOnUiThread {
+ startActivity(Intent(this@SplashScreen,
+ DashboardActivity::class.java))
+ finish()
+ }
+ }
+ })
+ }
+
+ private fun proceed() {
+ val user: UserInfo? = HungryDatabase.getDB(this@SplashScreen)
+ .UserInfoDao().getLoggedUser()
+
+ runOnUiThread {
+ if(user == null) {
+ startActivity(Intent(this@SplashScreen, LoginActivity::class.java))
+ finish()
+ } else {
+ fetchCurrentCoordinates()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/adapter/CollectionsAdapter.kt b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/CollectionsAdapter.kt
new file mode 100644
index 0000000..a4b96b5
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/CollectionsAdapter.kt
@@ -0,0 +1,57 @@
+package com.soumya.wwdablu.hungry.adapter
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.databinding.DataBindingUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.databinding.ItemCollectionLongBinding
+import com.soumya.wwdablu.hungry.iface.CollectionItemSelector
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionInfo
+import com.soumya.wwdablu.hungry.network.model.collections.CuratedCollection
+
+class CollectionsAdapter(list: List, listener: CollectionItemSelector) :
+ RecyclerView.Adapter() {
+
+ private val mCollectionList: List = list
+ private val mListener: CollectionItemSelector = listener
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CollectionViewHolder {
+
+ val viewBinding: ItemCollectionLongBinding = DataBindingUtil.inflate(
+ LayoutInflater.from(parent.context), R.layout.item_collection_long, parent, false)
+
+ return CollectionViewHolder(viewBinding)
+ }
+
+ override fun onBindViewHolder(holder: CollectionViewHolder, position: Int) {
+ holder.bind(mCollectionList[position].collection)
+ }
+
+ override fun getItemCount(): Int {
+ return mCollectionList.size
+ }
+
+ inner class CollectionViewHolder(viewBinding: ItemCollectionLongBinding) :
+ RecyclerView.ViewHolder(viewBinding.root) {
+
+ private val mViewBinding: ItemCollectionLongBinding = viewBinding
+
+ init {
+ mViewBinding.root.setOnClickListener {
+ mListener.onCollectionClicked(mCollectionList[adapterPosition].collection)
+ }
+ }
+
+ fun bind(collection: CollectionInfo) {
+
+ mViewBinding.collection = collection
+
+ Glide.with(mViewBinding.ivCollectionImage.context)
+ .load(collection.imageUrl)
+ .placeholder(R.drawable.default_card_bg)
+ .into(mViewBinding.ivCollectionImage)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/adapter/CuratedCollectionsAdapter.kt b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/CuratedCollectionsAdapter.kt
new file mode 100644
index 0000000..77d1662
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/CuratedCollectionsAdapter.kt
@@ -0,0 +1,63 @@
+package com.soumya.wwdablu.hungry.adapter
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.databinding.DataBindingUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.databinding.ItemCuratedCollectionBinding
+import com.soumya.wwdablu.hungry.iface.CollectionItemSelector
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionInfo
+import com.soumya.wwdablu.hungry.network.model.collections.CuratedCollection
+
+class CuratedCollectionsAdapter(list: List, listener: CollectionItemSelector) :
+ RecyclerView.Adapter() {
+
+ private val MAX_COLLECTION_CARDS: Int = 6
+
+ private val mCollectionList: List = list
+ private val mListener: CollectionItemSelector = listener
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CollectionViewHolder {
+
+ val viewBinding: ItemCuratedCollectionBinding = DataBindingUtil.inflate(
+ LayoutInflater.from(parent.context), R.layout.item_curated_collection, parent, false)
+
+ return CollectionViewHolder(viewBinding)
+ }
+
+ override fun onBindViewHolder(holder: CollectionViewHolder, position: Int) {
+ holder.bind(mCollectionList[position].collection)
+ }
+
+ override fun getItemCount(): Int {
+ return if(mCollectionList.size >= MAX_COLLECTION_CARDS) {
+ MAX_COLLECTION_CARDS
+ } else {
+ mCollectionList.size
+ }
+ }
+
+ inner class CollectionViewHolder(viewBinding: ItemCuratedCollectionBinding) :
+ RecyclerView.ViewHolder(viewBinding.root) {
+
+ private val mViewBinding: ItemCuratedCollectionBinding = viewBinding
+
+ init {
+ mViewBinding.root.setOnClickListener {
+ mListener.onCollectionClicked(mCollectionList[adapterPosition].collection)
+ }
+ }
+
+ fun bind(collectionInfo: CollectionInfo) {
+
+ mViewBinding.collection = collectionInfo
+
+ Glide.with(mViewBinding.ivCollectionImage.context)
+ .load(collectionInfo.imageUrl)
+ .placeholder(R.drawable.default_card_bg)
+ .into(mViewBinding.ivCollectionImage)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/adapter/GenericSearchResultAdapter.kt b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/GenericSearchResultAdapter.kt
new file mode 100644
index 0000000..cbf1461
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/GenericSearchResultAdapter.kt
@@ -0,0 +1,104 @@
+package com.soumya.wwdablu.hungry.adapter
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.soumya.wwdablu.hungry.databinding.CardResInfoBinding
+import com.soumya.wwdablu.hungry.iface.RestaurantItemSelector
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import com.soumya.wwdablu.hungry.utils.RestaurantInfoUtil
+import timber.log.Timber
+
+internal class GenericSearchResultAdapter(searchModel: SearchModel, listener: RestaurantItemSelector) :
+ RecyclerView.Adapter() {
+
+ private val mSearchModel: SearchModel = searchModel
+ private val mListener: RestaurantItemSelector = listener
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GenericSearchViewHolder {
+
+ return GenericSearchViewHolder(CardResInfoBinding.inflate(LayoutInflater.from(parent.context),
+ parent, false))
+ }
+
+ override fun onBindViewHolder(holder: GenericSearchViewHolder, position: Int) {
+ holder.bind(mSearchModel.restaurants[position].restaurant)
+ }
+
+ override fun getItemCount(): Int {
+ return mSearchModel.restaurants.size
+ }
+
+ fun handleTouchEvent(motionEvent: MotionEvent, viewHolder: RecyclerView.ViewHolder) {
+
+ val holder: GenericSearchViewHolder = viewHolder as GenericSearchViewHolder
+
+ when (motionEvent.actionMasked) {
+
+ MotionEvent.ACTION_DOWN -> {
+ holder.onTouchDown()
+ }
+
+ MotionEvent.ACTION_MOVE -> {
+ holder.onTouchMove()
+ }
+
+ MotionEvent.ACTION_UP -> {
+ holder.onTouchUp()
+ }
+ }
+ }
+
+ inner class GenericSearchViewHolder(viewBinding: CardResInfoBinding) :
+ RecyclerView.ViewHolder(viewBinding.root) {
+
+ private val mViewBinding: CardResInfoBinding = viewBinding
+
+ init {
+
+ mViewBinding.ivBookmark.setOnClickListener {
+ //
+ }
+
+ mViewBinding.root.setOnClickListener {
+ mListener.onRestaurantClicked(mSearchModel.restaurants[adapterPosition].restaurant)
+ }
+ }
+
+ fun onTouchDown() {
+
+ Timber.e("${mViewBinding.resName.text}")
+ mViewBinding.cvRestaurant.shrinkCard()
+ }
+
+ fun onTouchMove() {
+ //
+ }
+
+ fun onTouchUp() {
+ mViewBinding.cvRestaurant.expandCard()
+ }
+
+ @SuppressLint("SetTextI18n")
+ fun bind(restaurant: RestaurantInfo) {
+
+ mViewBinding.resName.text = restaurant.name
+ mViewBinding.resCuisines.text = restaurant.cuisines
+ mViewBinding.resLocation.text = "${restaurant.location.locality}, ${restaurant.location.city}"
+ mViewBinding.resAvgCost.text = "${restaurant.averageCostForTwo}"
+ mViewBinding.resTiming.text = restaurant.timings.split(",")[0]
+
+ mViewBinding.tvDistance.text = RestaurantInfo.calculateDistance(
+ restaurant.location.latitude, restaurant.location.longitude,
+ HungryRepo.getLocation().first, HungryRepo.getLocation().second
+ )
+
+ RestaurantInfoUtil.loadFeatureImage(mViewBinding.ivRestaurantImage, restaurant)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/adapter/PhotosAdapter.kt b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/PhotosAdapter.kt
new file mode 100644
index 0000000..83231d5
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/PhotosAdapter.kt
@@ -0,0 +1,53 @@
+package com.soumya.wwdablu.hungry.adapter
+
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.activity.PhotoViewerActivity
+import com.soumya.wwdablu.hungry.databinding.ItemResPhotoBinding
+
+class PhotosAdapter(urlList: List) : RecyclerView.Adapter() {
+
+ private val mUrlList: List = urlList
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotosViewModel {
+
+ val viewBinding: ItemResPhotoBinding = ItemResPhotoBinding.inflate(LayoutInflater.from(parent.context),
+ parent, false)
+
+ return PhotosViewModel(viewBinding)
+ }
+
+ override fun onBindViewHolder(holder: PhotosViewModel, position: Int) {
+ holder.bind(mUrlList[position])
+ }
+
+ override fun getItemCount(): Int {
+ return mUrlList.size
+ }
+
+ inner class PhotosViewModel(viewBinding: ItemResPhotoBinding) : RecyclerView.ViewHolder(viewBinding.root) {
+
+ private val mViewBinding: ItemResPhotoBinding = viewBinding
+
+ init {
+ mViewBinding.root.setOnClickListener {
+ val intent: Intent = Intent(viewBinding.root.context, PhotoViewerActivity::class.java)
+ intent.putStringArrayListExtra("list", ArrayList(mUrlList))
+ intent.putExtra("index", adapterPosition)
+ viewBinding.root.context.startActivity(intent)
+ }
+ }
+
+ fun bind(url: String) {
+
+ Glide.with(mViewBinding.ivResPhoto.context)
+ .load(url)
+ .placeholder(R.drawable.default_card_bg)
+ .into(mViewBinding.ivResPhoto)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/adapter/ReviewAdapter.kt b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/ReviewAdapter.kt
new file mode 100644
index 0000000..dd11c82
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/ReviewAdapter.kt
@@ -0,0 +1,43 @@
+package com.soumya.wwdablu.hungry.adapter
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.databinding.ItemReviewInfoBinding
+import com.soumya.wwdablu.hungry.network.model.reviews.Review
+import com.soumya.wwdablu.hungry.network.model.reviews.ReviewModel
+
+class ReviewAdapter(reviewModel: ReviewModel) : RecyclerView.Adapter() {
+
+ private val mReviewModel: ReviewModel = reviewModel
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReviewViewHolder {
+
+ return ReviewViewHolder(ItemReviewInfoBinding.inflate(LayoutInflater.from(parent.context),
+ parent, false))
+ }
+
+ override fun onBindViewHolder(holder: ReviewViewHolder, position: Int) {
+ holder.bind(mReviewModel.reviewList[position].review)
+ }
+
+ override fun getItemCount(): Int {
+ return mReviewModel.reviewList.size
+ }
+
+ inner class ReviewViewHolder(viewBinding: ItemReviewInfoBinding) : RecyclerView.ViewHolder(viewBinding.root) {
+
+ private val mViewBinding: ItemReviewInfoBinding = viewBinding
+
+ fun bind(review: Review) {
+ mViewBinding.review = review
+
+ Glide.with(mViewBinding.ivUserImage.context)
+ .load(review.user.profileImage)
+ .placeholder(R.mipmap.ic_launcher_round)
+ .into(mViewBinding.ivUserImage)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/adapter/SearchAdapter.kt b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/SearchAdapter.kt
new file mode 100644
index 0000000..7c32da5
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/adapter/SearchAdapter.kt
@@ -0,0 +1,138 @@
+package com.soumya.wwdablu.hungry.adapter
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.soumya.wwdablu.hungry.databinding.ItemSearchCuisineBinding
+import com.soumya.wwdablu.hungry.databinding.ItemSearchResBinding
+import com.soumya.wwdablu.hungry.databinding.ItemSearchResHeaderBinding
+import com.soumya.wwdablu.hungry.iface.CuisineItemSelector
+import com.soumya.wwdablu.hungry.iface.RestaurantItemSelector
+import com.soumya.wwdablu.hungry.network.model.cuisine.Cuisine
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import com.soumya.wwdablu.hungry.utils.RestaurantInfoUtil
+import java.util.*
+
+class SearchAdapter(cuisineList: List, searchModel: SearchModel,
+ resListener: RestaurantItemSelector, cuisineItemSelector: CuisineItemSelector) :
+ RecyclerView.Adapter() {
+
+ private val mResListener: RestaurantItemSelector = resListener
+ private val mCuisineItemSelector: CuisineItemSelector = cuisineItemSelector
+
+ private enum class ViewType {
+ Cuisine,
+ RestaurantHeader,
+ Restaurant
+ }
+
+ private val mCuisineList: LinkedList = LinkedList(cuisineList)
+ private var mSearchModel: SearchModel? = searchModel
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseSearchViewHolder {
+
+ val inflater: LayoutInflater = LayoutInflater.from(parent.context)
+ return when (ViewType.values()[viewType]) {
+ ViewType.Cuisine -> {
+ SearchCuisineViewHolder(ItemSearchCuisineBinding.inflate(inflater, parent, false))
+ }
+ ViewType.Restaurant -> {
+ SearchResViewHolder(ItemSearchResBinding.inflate(inflater, parent, false))
+ }
+ ViewType.RestaurantHeader -> {
+ SearchResHeaderViewHolder(ItemSearchResHeaderBinding.inflate(inflater, parent, false))
+ }
+ }
+ }
+
+ override fun onBindViewHolder(holder: BaseSearchViewHolder, position: Int) {
+ holder.bind(position)
+ }
+
+ override fun getItemCount(): Int {
+ return mCuisineList.size + (mSearchModel?.restaurants?.size ?: 0) +
+ if(mSearchModel == null) 0 else 1
+ }
+
+ override fun getItemViewType(position: Int): Int {
+
+ return when {
+ mCuisineList.size >= position + 1 -> {
+ ViewType.Cuisine.ordinal
+ }
+ position == mCuisineList.size -> {
+ ViewType.RestaurantHeader.ordinal
+ }
+ else -> {
+ ViewType.Restaurant.ordinal
+ }
+ }
+ }
+
+ fun setSearchResults(list: List, searchResult: SearchModel?) {
+
+ mCuisineList.clear()
+ mCuisineList.addAll(list)
+
+ mSearchModel = searchResult
+
+ notifyDataSetChanged()
+ }
+
+ inner class SearchCuisineViewHolder(viewBinding: ItemSearchCuisineBinding) :
+ BaseSearchViewHolder(viewBinding.root) {
+
+ private val mViewBinding: ItemSearchCuisineBinding = viewBinding
+
+ init {
+ mViewBinding.root.setOnClickListener {
+ mCuisineItemSelector.onCuisineClicked(mCuisineList[adapterPosition])
+ }
+ }
+
+ override fun bind(position: Int) {
+
+ mViewBinding.cuisine = mCuisineList[position]
+ }
+ }
+
+ inner class SearchResViewHolder(viewBinding: ItemSearchResBinding) :
+ BaseSearchViewHolder(viewBinding.root) {
+
+ private val mViewBinding: ItemSearchResBinding = viewBinding
+
+ init {
+ mViewBinding.root.setOnClickListener {
+ val restaurant = getRestaurant() ?: return@setOnClickListener
+ mResListener.onRestaurantClicked(restaurant)
+ }
+ }
+
+ override fun bind(position: Int) {
+
+ val restaurant = getRestaurant() ?: return
+ mViewBinding.resInfo = restaurant
+
+ RestaurantInfoUtil.loadFeatureImage(mViewBinding.ivCuisine, restaurant, false)
+ }
+
+ private fun getRestaurant() : RestaurantInfo? {
+ val index = adapterPosition - mCuisineList.size - 1
+ return mSearchModel?.restaurants?.get(index)?.restaurant
+ }
+ }
+
+ inner class SearchResHeaderViewHolder(viewBinding: ItemSearchResHeaderBinding) :
+ BaseSearchViewHolder(viewBinding.root) {
+
+ override fun bind(position: Int) {
+ //
+ }
+ }
+
+ abstract class BaseSearchViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ abstract fun bind(position: Int)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/customview/DashboardBottomNaviView.kt b/app/src/main/java/com/soumya/wwdablu/hungry/customview/DashboardBottomNaviView.kt
new file mode 100644
index 0000000..fe87384
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/customview/DashboardBottomNaviView.kt
@@ -0,0 +1,124 @@
+package com.soumya.wwdablu.hungry.customview
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Menu
+import android.view.MenuItem
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.defines.CategoryEnum
+import com.soumya.wwdablu.hungry.network.model.categories.Categories
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import timber.log.Timber
+import java.util.*
+
+class DashboardBottomNaviView : BottomNavigationView {
+
+ private lateinit var mCategoriesList: List
+
+ companion object {
+ const val ProfileMenu: Int = 99
+ }
+
+ constructor(context: Context) : super(context) {
+ fetchCategories()
+ }
+
+ constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
+ fetchCategories()
+ }
+
+ constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
+ fetchCategories()
+ }
+
+ private fun prepareMenu() {
+
+ val pair: Pair = getFoodType()
+
+ menu.add(Menu.NONE, CategoryEnum.Recommended.ordinal, Menu.NONE, context.getString(R.string.menu_order))
+ .setIcon(R.drawable.ic_recommended)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+
+ selectedItemId = CategoryEnum.Recommended.ordinal
+
+ for(categories: Categories in mCategoriesList) {
+
+ if(pair.first.id == categories.category.id) {
+
+ menu.add(Menu.NONE, categories.category.id, Menu.NONE,categories.category.name)
+ .setIcon(pair.first.icon())
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+ }
+
+ else if(pair.second != null && pair.second!!.id == categories.category.id) {
+
+ menu.add(Menu.NONE, categories.category.id, Menu.NONE,categories.category.name)
+ .setIcon(pair.second!!.icon())
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+ }
+ }
+
+ menu.add(Menu.NONE, ProfileMenu, Menu.NONE, context.getString(R.string.menu_profile))
+ .setIcon(R.drawable.ic_profile)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+ }
+
+ private fun getFoodType() : Pair {
+
+ var hourOfDay = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
+ return when (hourOfDay) {
+
+ in 0..4 -> {
+ Pair(CategoryEnum.Nightlife, CategoryEnum.PubAndBar)
+ }
+
+ in 5..9 -> {
+ Pair(CategoryEnum.Breakfast, null)
+ }
+
+ in 10..11 -> {
+ Pair(CategoryEnum.Breakfast, CategoryEnum.Lunch)
+ }
+
+ in 12..15 -> {
+ Pair(CategoryEnum.Lunch, null)
+ }
+
+ in 16..18 -> {
+ Pair(CategoryEnum.Cafes, CategoryEnum.CatchingUp)
+ }
+
+ in 19..23 -> {
+ Pair(CategoryEnum.Dinner, null)
+ }
+
+ else -> {
+ Pair(CategoryEnum.PubAndBar, CategoryEnum.Nightlife)
+ }
+ }
+ }
+
+ private fun fetchCategories() {
+
+ HungryRepo.getCategories()
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver>() {
+ override fun onNext(t: List?) {
+ mCategoriesList = t ?: LinkedList()
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ }
+
+ override fun onComplete() {
+ prepareMenu()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/customview/RestaurantCard.kt b/app/src/main/java/com/soumya/wwdablu/hungry/customview/RestaurantCard.kt
new file mode 100644
index 0000000..697b3d1
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/customview/RestaurantCard.kt
@@ -0,0 +1,44 @@
+package com.soumya.wwdablu.hungry.customview
+
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import androidx.cardview.widget.CardView
+import kotlin.math.abs
+
+
+class RestaurantCard : CardView {
+
+ constructor(context: Context) : super(context) {
+ //
+ }
+
+ constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
+ //
+ }
+
+ constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
+ //
+ }
+
+ fun shrinkCard() {
+ animateScaling(0.95f, 0.95f)
+ }
+
+ fun expandCard() {
+ animateScaling(1f, 1f)
+ }
+
+ private fun animateScaling(x: Float, y: Float) {
+ val scaleX = ObjectAnimator.ofFloat(this, "scaleX", x)
+ val scaleY = ObjectAnimator.ofFloat(this, "scaleY", y)
+ scaleX.duration = 200
+ scaleY.duration = 200
+
+ val scaleDown = AnimatorSet()
+ scaleDown.play(scaleX).with(scaleY)
+ scaleDown.start()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/customview/RestaurantDetailsBottomNaviView.kt b/app/src/main/java/com/soumya/wwdablu/hungry/customview/RestaurantDetailsBottomNaviView.kt
new file mode 100644
index 0000000..c1f1ada
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/customview/RestaurantDetailsBottomNaviView.kt
@@ -0,0 +1,45 @@
+package com.soumya.wwdablu.hungry.customview
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Menu
+import android.view.MenuItem
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.soumya.wwdablu.hungry.R
+
+class RestaurantDetailsBottomNaviView : BottomNavigationView {
+
+ enum class MenuItems {
+ Overview,
+ Menu,
+ Photos,
+ Reviews
+ }
+
+ constructor(context: Context) : super(context) {
+ prepareMenu()
+ }
+
+ constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
+ prepareMenu()
+ }
+
+ constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr) {
+ prepareMenu()
+ }
+
+ private fun prepareMenu() {
+
+ menu.add(Menu.NONE, MenuItems.Overview.ordinal, Menu.NONE, context.getString(R.string.menu_overview))
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+
+ menu.add(Menu.NONE, MenuItems.Menu.ordinal, Menu.NONE, context.getString(R.string.menu_foodmenu))
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+
+ menu.add(Menu.NONE, MenuItems.Photos.ordinal, Menu.NONE, context.getString(R.string.menu_photos))
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+
+ menu.add(Menu.NONE, MenuItems.Reviews.ordinal, Menu.NONE, context.getString(R.string.menu_reviews))
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/database/HungryAppDatabase.kt b/app/src/main/java/com/soumya/wwdablu/hungry/database/HungryAppDatabase.kt
new file mode 100644
index 0000000..ed5561f
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/database/HungryAppDatabase.kt
@@ -0,0 +1,12 @@
+package com.soumya.wwdablu.hungry.database
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+import com.soumya.wwdablu.hungry.database.userinfo.UserInfo
+import com.soumya.wwdablu.hungry.database.userinfo.UserInfoDao
+
+@Database(entities = [UserInfo::class], exportSchema = false, version = 1)
+abstract class HungryAppDatabase : RoomDatabase() {
+
+ abstract fun UserInfoDao() : UserInfoDao
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/database/HungryDatabase.kt b/app/src/main/java/com/soumya/wwdablu/hungry/database/HungryDatabase.kt
new file mode 100644
index 0000000..9c4a89c
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/database/HungryDatabase.kt
@@ -0,0 +1,25 @@
+package com.soumya.wwdablu.hungry.database
+
+import android.content.Context
+import androidx.room.Room
+
+object HungryDatabase {
+
+ private var INSTANCE: HungryAppDatabase? = null
+
+ @Synchronized
+ fun getDB(context: Context) : HungryAppDatabase {
+
+ if(INSTANCE == null) {
+ INSTANCE = buildRoomDatabase(context)
+ }
+
+ return INSTANCE!!
+ }
+
+ private fun buildRoomDatabase(context: Context) : HungryAppDatabase {
+
+ return Room.databaseBuilder(context, HungryAppDatabase::class.java, "hungry.db")
+ .build()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/database/userinfo/UserInfo.kt b/app/src/main/java/com/soumya/wwdablu/hungry/database/userinfo/UserInfo.kt
new file mode 100644
index 0000000..ca9b0fa
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/database/userinfo/UserInfo.kt
@@ -0,0 +1,18 @@
+package com.soumya.wwdablu.hungry.database.userinfo
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+@Entity(tableName = "user_info")
+data class UserInfo(
+ @PrimaryKey(autoGenerate = true)
+ @ColumnInfo(name = "id")
+ val _id: Long = -1L,
+
+ @ColumnInfo(name = "is_loggedin")
+ var isLoggedIn: Boolean,
+
+ @ColumnInfo(name = "user_identifier")
+ val userIdentifier: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/database/userinfo/UserInfoDao.kt b/app/src/main/java/com/soumya/wwdablu/hungry/database/userinfo/UserInfoDao.kt
new file mode 100644
index 0000000..2a54063
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/database/userinfo/UserInfoDao.kt
@@ -0,0 +1,22 @@
+package com.soumya.wwdablu.hungry.database.userinfo
+
+import androidx.room.*
+
+@Dao
+interface UserInfoDao {
+
+ @Query("SELECT * FROM user_info WHERE is_loggedin = 1")
+ fun getLoggedUser() : UserInfo?
+
+ @Query("SELECT * FROM USER_INFO WHERE user_identifier = :userId")
+ fun isUserRegistered(userId: String) : UserInfo?
+
+ @Insert
+ fun registerLoggedInUser(userInfo: UserInfo)
+
+ @Update
+ fun updateLoginStatus(userInfo: UserInfo)
+
+ @Delete
+ fun removeUser(userInfo: UserInfo)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/defines/CategoryEnum.kt b/app/src/main/java/com/soumya/wwdablu/hungry/defines/CategoryEnum.kt
new file mode 100644
index 0000000..09635e9
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/defines/CategoryEnum.kt
@@ -0,0 +1,64 @@
+package com.soumya.wwdablu.hungry.defines
+
+import com.soumya.wwdablu.hungry.R
+
+enum class CategoryEnum(val id: Int) {
+ Delivery(1) {
+ override fun icon() : Int {
+ return R.drawable.ic_delivery
+ }},
+ Dineout(2) {
+ override fun icon() : Int {
+ return R.drawable.ic_dining
+ }},
+ Nightlife(3) {
+ override fun icon() : Int {
+ return R.drawable.ic_nightlife
+ }},
+ CatchingUp(4) {
+ override fun icon() : Int {
+ return R.drawable.ic_pub
+ }},
+ TakeAway(5) {
+ override fun icon() : Int {
+ return R.drawable.ic_takeout
+ }},
+ Cafes(6) {
+ override fun icon() : Int {
+ return R.drawable.ic_cafe
+ }},
+ DailyMenus(7) {
+ override fun icon() : Int {
+ return R.drawable.ic_dining
+ }},
+ Breakfast(8) {
+ override fun icon() : Int {
+ return R.drawable.ic_breakfast
+ }},
+ Lunch(9) {
+ override fun icon() : Int {
+ return R.drawable.ic_lunch
+ }},
+ Dinner(10) {
+ override fun icon() : Int {
+ return R.drawable.ic_dinner
+ }},
+ PubAndBar(11) {
+ override fun icon() : Int {
+ return R.drawable.ic_pub
+ }},
+ PocketFriendlyDelivery(13) {
+ override fun icon() : Int {
+ return R.drawable.ic_delivery
+ }},
+ ClubAndLounge(14) {
+ override fun icon() : Int {
+ return R.drawable.ic_pub
+ }},
+ Recommended(999) {
+ override fun icon() : Int {
+ return R.drawable.ic_recommended
+ }};
+
+ abstract fun icon() : Int
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/defines/SearchBy.kt b/app/src/main/java/com/soumya/wwdablu/hungry/defines/SearchBy.kt
new file mode 100644
index 0000000..65a50db
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/defines/SearchBy.kt
@@ -0,0 +1,9 @@
+package com.soumya.wwdablu.hungry.defines
+
+enum class SearchBy {
+ Collection,
+ Category,
+ Cuisine,
+ Query,
+ None
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/fragment/GenericSearchResultFragment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/GenericSearchResultFragment.kt
new file mode 100644
index 0000000..80039d7
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/GenericSearchResultFragment.kt
@@ -0,0 +1,195 @@
+package com.soumya.wwdablu.hungry.fragment
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.soumya.wwdablu.hungry.activity.RestaurantDetailsActivity
+import com.soumya.wwdablu.hungry.activity.SearchActivity
+import com.soumya.wwdablu.hungry.adapter.GenericSearchResultAdapter
+import com.soumya.wwdablu.hungry.databinding.FragSearchResultGenericBinding
+import com.soumya.wwdablu.hungry.defines.CategoryEnum
+import com.soumya.wwdablu.hungry.defines.SearchBy
+import com.soumya.wwdablu.hungry.iface.RestaurantItemSelector
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import timber.log.Timber
+
+class GenericSearchResultFragment private constructor() : HungryFragment(),
+ RestaurantItemSelector {
+
+ private lateinit var mGenericSearchResultAdapter: GenericSearchResultAdapter
+ private lateinit var mSearchModel: SearchModel
+
+ private lateinit var mPrimarySearchCriteria: Pair
+ private lateinit var mFallbackSearchCriteria: Pair
+
+ companion object {
+
+ fun newInstance(primarySearch: SearchBy, primarySearchParam: String,
+ fallbackSearch: SearchBy = SearchBy.None, fallbackSearchParam: String = "")
+ : GenericSearchResultFragment {
+
+ val fragment = GenericSearchResultFragment()
+
+ fragment.mPrimarySearchCriteria = Pair(primarySearch, primarySearchParam)
+ fragment.mFallbackSearchCriteria = Pair(fallbackSearch, fallbackSearchParam)
+
+ return fragment
+ }
+ }
+
+ override fun onCreateViewExt(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+
+ mViewBinding = FragSearchResultGenericBinding.inflate(inflater, container, false)
+
+ mViewBinding.rvCatList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
+ mViewBinding.rvCatList.addOnItemTouchListener(mItemTouchListener)
+
+ if(this::mSearchModel.isInitialized) {
+ mViewBinding.rvCatList.adapter = mGenericSearchResultAdapter
+ }
+
+ mViewBinding.searchBar.rlSearchContainer.setOnClickListener {
+ startActivity(Intent(context, SearchActivity::class.java))
+ }
+
+ getDataBySearchMode()
+
+ mViewBinding.city = HungryRepo.getCityModel().model[0]
+
+ return mViewBinding.root
+ }
+
+ private fun getDataBySearchMode() {
+
+ when (mPrimarySearchCriteria.first) {
+
+ SearchBy.Category -> {
+ getByCategory(CategoryEnum.valueOf(mPrimarySearchCriteria.second))
+ }
+
+ SearchBy.Collection -> {
+ if(mPrimarySearchCriteria.second.isNotEmptyAndNotBlank()) {
+ getByCollectionId(mPrimarySearchCriteria.second.toInt())
+ }
+ }
+
+ SearchBy.Cuisine -> {
+ if(mPrimarySearchCriteria.second.isNotEmptyAndNotBlank()) {
+ getByCuisineId(mPrimarySearchCriteria.second)
+ }
+ }
+
+ SearchBy.Query -> {
+ if(mPrimarySearchCriteria.second.isNotEmptyAndNotBlank()) {
+ getByQuery(mPrimarySearchCriteria.second)
+ }
+ }
+
+ SearchBy.None -> {
+ Timber.e("Primary search mode is given as None")
+ }
+ }
+ }
+
+ private fun getByCategory(categoryEnum: CategoryEnum) {
+
+ HungryRepo.searchByCategoryId(categoryEnum)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: GenericObserver() {
+ override fun onNext(t: SearchModel?) {
+ if(t != null) {
+ mSearchModel = t
+ mGenericSearchResultAdapter = GenericSearchResultAdapter(t, this@GenericSearchResultFragment)
+ } else {
+ getByCollectionId(if(mFallbackSearchCriteria.second.isEmptyOrBlank()) 1 else
+ mFallbackSearchCriteria.second.toInt())
+ }
+ }
+ })
+ }
+
+ private fun getByCollectionId(collectionId: Int) {
+
+ HungryRepo.searchByCollectionId(collectionId)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(GenericObserver())
+ }
+
+ private fun getByCuisineId(cuisineId: String) {
+
+ HungryRepo.searchByCuisineId(cuisineId)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(GenericObserver())
+ }
+
+ private fun getByQuery(query: String) {
+
+ HungryRepo.search(query)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(GenericObserver())
+ }
+
+ private val mItemTouchListener: RecyclerView.OnItemTouchListener = object: RecyclerView.OnItemTouchListener {
+ override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
+
+ val view: View = rv.findChildViewUnder(e.x, e.y) ?: return false
+ val viewHolder: RecyclerView.ViewHolder = rv.findContainingViewHolder(view) ?: return false
+ mGenericSearchResultAdapter.handleTouchEvent(e, viewHolder)
+
+ return false
+ }
+
+ override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
+ //
+ }
+
+ override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
+ //
+ }
+ }
+
+ private open inner class GenericObserver : DisposableObserver() {
+ override fun onNext(t: SearchModel?) {
+ if(t != null) {
+ mSearchModel = t
+ mGenericSearchResultAdapter = GenericSearchResultAdapter(t, this@GenericSearchResultFragment)
+ }
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ }
+
+ override fun onComplete() {
+ if(this@GenericSearchResultFragment::mGenericSearchResultAdapter.isInitialized) {
+ mViewBinding.lotLoading.cancelAnimation()
+ mViewBinding.lotLoading.visibility = View.GONE
+ mViewBinding.rvCatList.visibility = View.VISIBLE
+ mViewBinding.rvCatList.adapter = mGenericSearchResultAdapter
+ }
+ }
+ }
+
+ override fun onRestaurantClicked(restaurant: RestaurantInfo) {
+
+ activity?.runOnUiThread {
+ val intent: Intent = Intent(context, RestaurantDetailsActivity::class.java)
+ intent.putExtra("res_details", restaurant)
+ startActivity(intent)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/fragment/HungryFragment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/HungryFragment.kt
new file mode 100644
index 0000000..bc32b45
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/HungryFragment.kt
@@ -0,0 +1,32 @@
+package com.soumya.wwdablu.hungry.fragment
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.viewbinding.ViewBinding
+
+abstract class HungryFragment : Fragment() {
+
+ protected lateinit var mViewBinding: T
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+
+ if(this::mViewBinding.isInitialized) {
+ return mViewBinding.root
+ }
+
+ return onCreateViewExt(inflater, container, savedInstanceState)
+ }
+
+ protected fun String.isEmptyOrBlank() : Boolean {
+ return isEmpty() || isBlank()
+ }
+
+ protected fun String.isNotEmptyAndNotBlank() : Boolean {
+ return isNotEmpty() && isNotBlank()
+ }
+
+ abstract fun onCreateViewExt(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/fragment/ProfileFragment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/ProfileFragment.kt
new file mode 100644
index 0000000..9da11ec
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/ProfileFragment.kt
@@ -0,0 +1,24 @@
+package com.soumya.wwdablu.hungry.fragment
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.soumya.wwdablu.hungry.databinding.FragProfileBinding
+
+class ProfileFragment private constructor() : HungryFragment() {
+
+ companion object {
+
+ fun newInstance() : ProfileFragment {
+ return ProfileFragment()
+ }
+ }
+
+ override fun onCreateViewExt(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+
+ mViewBinding = FragProfileBinding.inflate(inflater, container, false)
+
+ return mViewBinding.root
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/fragment/RecommendedFragment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/RecommendedFragment.kt
new file mode 100644
index 0000000..26f5d7f
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/RecommendedFragment.kt
@@ -0,0 +1,162 @@
+package com.soumya.wwdablu.hungry.fragment
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.soumya.wwdablu.hungry.activity.CollectionDetailsActivity
+import com.soumya.wwdablu.hungry.activity.CollectionsActivity
+import com.soumya.wwdablu.hungry.activity.RestaurantDetailsActivity
+import com.soumya.wwdablu.hungry.activity.SearchActivity
+import com.soumya.wwdablu.hungry.adapter.CuratedCollectionsAdapter
+import com.soumya.wwdablu.hungry.databinding.FragRecommendedBinding
+import com.soumya.wwdablu.hungry.adapter.GenericSearchResultAdapter
+import com.soumya.wwdablu.hungry.iface.CollectionItemSelector
+import com.soumya.wwdablu.hungry.iface.RestaurantItemSelector
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionInfo
+import com.soumya.wwdablu.hungry.network.model.collections.CuratedCollection
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import timber.log.Timber
+
+class RecommendedFragment private constructor() : HungryFragment(),
+ RestaurantItemSelector, CollectionItemSelector {
+
+ private lateinit var mCollectionAdapter: CuratedCollectionsAdapter
+ private lateinit var mGenericSearchResultAdapter: GenericSearchResultAdapter
+
+ companion object {
+
+ fun newInstance() : RecommendedFragment {
+ return RecommendedFragment()
+ }
+ }
+
+ override fun onCreateViewExt(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+
+ mViewBinding = FragRecommendedBinding.inflate(inflater, container, false)
+ mViewBinding.city = HungryRepo.getCityModel().model[0]
+
+ mViewBinding.rvCuratedCollection.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
+ getCollection()
+
+ mViewBinding.rvRecommendedForYou.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
+ mViewBinding.rvRecommendedForYou.addOnItemTouchListener(mItemTouchListener)
+ getRecommendation()
+
+ mViewBinding.tvCollectionSeeall.setOnClickListener {
+ startActivity(Intent(context, CollectionsActivity::class.java))
+ }
+
+ mViewBinding.searchBar.rlSearchContainer.setOnClickListener {
+ startActivity(Intent(context, SearchActivity::class.java))
+ }
+
+ return mViewBinding.root
+ }
+
+ private fun getRecommendation() {
+
+ HungryRepo.searchByCollectionId(1)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver() {
+ override fun onNext(t: SearchModel?) {
+
+ if(t == null) {
+ return
+ }
+
+ mGenericSearchResultAdapter = GenericSearchResultAdapter(t, this@RecommendedFragment)
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ }
+
+ override fun onComplete() {
+
+ if(this@RecommendedFragment::mGenericSearchResultAdapter.isInitialized) {
+ mViewBinding.lotRecommendedLoading.cancelAnimation()
+ mViewBinding.lotRecommendedLoading.visibility = View.GONE
+ mViewBinding.rvRecommendedForYou.visibility = View.VISIBLE
+ mViewBinding.rvRecommendedForYou.adapter = mGenericSearchResultAdapter
+ }
+ }
+ })
+ }
+
+ private fun getCollection() {
+
+ HungryRepo.getCollections()
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver>() {
+ override fun onNext(t: List?) {
+
+ if(t != null) {
+ mCollectionAdapter = CuratedCollectionsAdapter(t, this@RecommendedFragment)
+ }
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ }
+
+ override fun onComplete() {
+
+ if(this@RecommendedFragment::mCollectionAdapter.isInitialized) {
+ mViewBinding.lotCollectionLoading.cancelAnimation()
+ mViewBinding.lotCollectionLoading.visibility = View.GONE
+ mViewBinding.rvCuratedCollection.visibility = View.VISIBLE
+ mViewBinding.rvCuratedCollection.adapter = mCollectionAdapter
+ }
+ }
+ })
+ }
+
+ private val mItemTouchListener: RecyclerView.OnItemTouchListener = object: RecyclerView.OnItemTouchListener {
+ override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
+
+ val view: View = rv.findChildViewUnder(e.x, e.y) ?: return false
+ val viewHolder: RecyclerView.ViewHolder = rv.findContainingViewHolder(view) ?: return false
+ mGenericSearchResultAdapter.handleTouchEvent(e, viewHolder)
+
+ return false
+ }
+
+ override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
+ //
+ }
+
+ override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
+ //
+ }
+ }
+
+ override fun onRestaurantClicked(restaurant: RestaurantInfo) {
+
+ activity?.runOnUiThread {
+ val intent: Intent = Intent(context, RestaurantDetailsActivity::class.java)
+ intent.putExtra("res_details", restaurant)
+ startActivity(intent)
+ }
+ }
+
+ override fun onCollectionClicked(collection: CollectionInfo) {
+ activity?.runOnUiThread {
+ val intent: Intent = Intent(context, CollectionDetailsActivity::class.java)
+ intent.putExtra("collection_id", collection.id)
+ intent.putExtra("collection_info", collection)
+ startActivity(intent)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/OverviewFragment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/OverviewFragment.kt
new file mode 100644
index 0000000..ba6f212
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/OverviewFragment.kt
@@ -0,0 +1,55 @@
+package com.soumya.wwdablu.hungry.fragment.resdetails
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import androidx.appcompat.widget.AppCompatTextView
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.databinding.FragResOverviewBinding
+import com.soumya.wwdablu.hungry.fragment.HungryFragment
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.utils.RestaurantInfoUtil
+
+class OverviewFragment private constructor() : HungryFragment() {
+
+ private lateinit var mRestaurant: RestaurantInfo
+
+ companion object {
+
+ fun newInstance(restaurant: RestaurantInfo) : OverviewFragment {
+
+ val fragment = OverviewFragment()
+ fragment.mRestaurant = restaurant
+
+ return fragment
+ }
+ }
+
+ override fun onCreateViewExt(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+
+ mViewBinding = FragResOverviewBinding.inflate(inflater, container, false)
+ mViewBinding.resInfo = mRestaurant
+
+ populateOtherInfo(mViewBinding.root.context)
+
+ RestaurantInfoUtil.loadFeatureImage(mViewBinding.ivRestaurantImage, mRestaurant)
+
+ return mViewBinding.root
+ }
+
+ private fun populateOtherInfo(context: Context) {
+
+ mRestaurant.highlights.forEach {
+ val param: LinearLayout.LayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT)
+ val textView: AppCompatTextView = AppCompatTextView(context)
+ textView.layoutParams = param
+ textView.text = it
+ textView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_check, 0, 0, 0);
+ mViewBinding.llHighlightsContainer.addView(textView)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/PhotosFragment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/PhotosFragment.kt
new file mode 100644
index 0000000..b55b530
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/PhotosFragment.kt
@@ -0,0 +1,70 @@
+package com.soumya.wwdablu.hungry.fragment.resdetails
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.StaggeredGridLayoutManager
+import com.soumya.wwdablu.hungry.adapter.PhotosAdapter
+import com.soumya.wwdablu.hungry.databinding.FragResPhotoBinding
+import com.soumya.wwdablu.hungry.fragment.HungryFragment
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.utils.RestaurantInfoUtil
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import timber.log.Timber
+
+class PhotosFragment private constructor() : HungryFragment() {
+
+ private lateinit var mAdapter: PhotosAdapter
+ private lateinit var mPhotoUrls: List
+
+ companion object {
+
+ fun newInstance(restaurant: RestaurantInfo) : PhotosFragment {
+
+ val fragment = PhotosFragment()
+ fragment.getPhotos(restaurant)
+
+ return fragment
+ }
+ }
+
+ override fun onCreateViewExt(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+
+ mViewBinding = FragResPhotoBinding.inflate(inflater, container, false)
+ mViewBinding.rvPhotos.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
+
+ return mViewBinding.root
+ }
+
+ private fun getPhotos(restaurant: RestaurantInfo) {
+
+ RestaurantInfoUtil.getPhotos(restaurant)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver>() {
+ override fun onNext(t: List?) {
+
+ if(t == null) {
+ return
+ }
+
+ mPhotoUrls = t
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ }
+
+ override fun onComplete() {
+
+ if(this@PhotosFragment::mPhotoUrls.isInitialized) {
+ mAdapter = PhotosAdapter(mPhotoUrls)
+ mViewBinding.rvPhotos.adapter = mAdapter
+ }
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/ReviewFragment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/ReviewFragment.kt
new file mode 100644
index 0000000..ddd3867
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/fragment/resdetails/ReviewFragment.kt
@@ -0,0 +1,80 @@
+package com.soumya.wwdablu.hungry.fragment.resdetails
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.soumya.wwdablu.hungry.adapter.ReviewAdapter
+import com.soumya.wwdablu.hungry.databinding.FragResReviewsBinding
+import com.soumya.wwdablu.hungry.fragment.HungryFragment
+import com.soumya.wwdablu.hungry.network.model.reviews.ReviewModel
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.repository.HungryRepo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import timber.log.Timber
+
+class ReviewFragment private constructor() : HungryFragment() {
+
+ private lateinit var mReviewModel: ReviewModel
+ private lateinit var mAdapter: ReviewAdapter
+
+ private lateinit var mRestaurant: RestaurantInfo
+
+ companion object {
+
+ fun newInstance(restaurant: RestaurantInfo) : ReviewFragment {
+
+ val fragment = ReviewFragment()
+ fragment.mRestaurant = restaurant
+
+ return fragment
+ }
+ }
+
+ override fun onCreateViewExt(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+
+ mViewBinding = FragResReviewsBinding.inflate(inflater, container, false)
+ mViewBinding.resInfo = mRestaurant
+
+ mViewBinding.rvReviews.layoutManager = LinearLayoutManager(requireContext())
+ getReviews(mRestaurant.r.resId)
+
+ return mViewBinding.root
+ }
+
+ private fun getReviews(resId: Int) {
+
+ HungryRepo.getReviews(resId)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver() {
+ override fun onNext(t: ReviewModel?) {
+
+ if(t != null) {
+ mReviewModel = t
+ }
+ }
+
+ override fun onError(e: Throwable?) {
+ Timber.e(e)
+ }
+
+ override fun onComplete() {
+
+ if(this@ReviewFragment::mReviewModel.isInitialized) {
+
+ mViewBinding.lotRecommendedLoading.cancelAnimation()
+ mViewBinding.lotRecommendedLoading.visibility = View.GONE
+ mViewBinding.rvReviews.visibility = View.VISIBLE
+
+ mAdapter = ReviewAdapter(mReviewModel)
+ mViewBinding.rvReviews.adapter = mAdapter
+ mViewBinding.review = mReviewModel
+ }
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/iface/CollectionItemSelector.kt b/app/src/main/java/com/soumya/wwdablu/hungry/iface/CollectionItemSelector.kt
new file mode 100644
index 0000000..65878a8
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/iface/CollectionItemSelector.kt
@@ -0,0 +1,7 @@
+package com.soumya.wwdablu.hungry.iface
+
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionInfo
+
+interface CollectionItemSelector {
+ fun onCollectionClicked(collection: CollectionInfo)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/iface/CuisineItemSelector.kt b/app/src/main/java/com/soumya/wwdablu/hungry/iface/CuisineItemSelector.kt
new file mode 100644
index 0000000..a2979b0
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/iface/CuisineItemSelector.kt
@@ -0,0 +1,7 @@
+package com.soumya.wwdablu.hungry.iface
+
+import com.soumya.wwdablu.hungry.network.model.cuisine.Cuisine
+
+interface CuisineItemSelector {
+ fun onCuisineClicked(cuisine: Cuisine)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/iface/RestaurantItemSelector.kt b/app/src/main/java/com/soumya/wwdablu/hungry/iface/RestaurantItemSelector.kt
new file mode 100644
index 0000000..4d693e6
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/iface/RestaurantItemSelector.kt
@@ -0,0 +1,7 @@
+package com.soumya.wwdablu.hungry.iface
+
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+
+interface RestaurantItemSelector {
+ fun onRestaurantClicked(restaurant: RestaurantInfo)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/DataProvider.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/DataProvider.kt
new file mode 100644
index 0000000..d34b561
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/DataProvider.kt
@@ -0,0 +1,40 @@
+package com.soumya.wwdablu.hungry.network
+
+import com.soumya.wwdablu.hungry.BuildConfig
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import retrofit2.Retrofit
+import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
+import retrofit2.converter.gson.GsonConverterFactory
+
+object DataProvider {
+
+ private val mZomatoAPI: ZomatoAPI
+
+ init {
+ mZomatoAPI = Retrofit.Builder()
+ .baseUrl(BuildConfig.ZOMATO_BASE_URL)
+ .client(getHttpClient())
+ .addConverterFactory(GsonConverterFactory.create())
+ .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
+ .build()
+ .create(ZomatoAPI::class.java)
+ }
+
+ fun call() : ZomatoAPI {
+ return mZomatoAPI
+ }
+
+ private fun getHttpClient() : OkHttpClient {
+
+ return OkHttpClient.Builder()
+ .addInterceptor {
+ val request = it.request().newBuilder()
+ .addHeader("user-key", BuildConfig.ZOMATO_API_KEY)
+ .build()
+
+ it.proceed(request)
+ }
+ .build()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/ZomatoAPI.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/ZomatoAPI.kt
new file mode 100644
index 0000000..a6a28d9
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/ZomatoAPI.kt
@@ -0,0 +1,61 @@
+package com.soumya.wwdablu.hungry.network
+
+import com.soumya.wwdablu.hungry.network.model.categories.CategoriesModel
+import com.soumya.wwdablu.hungry.network.model.cities.CityModel
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionModel
+import com.soumya.wwdablu.hungry.network.model.cuisine.CuisineModel
+import com.soumya.wwdablu.hungry.network.model.establishments.EstablishmentModel
+import com.soumya.wwdablu.hungry.network.model.reviews.ReviewModel
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import io.reactivex.rxjava3.core.Observable
+import retrofit2.http.GET
+import retrofit2.http.Query
+
+interface ZomatoAPI {
+
+ @GET("/api/v2.1/categories")
+ fun getCategories() : Observable
+
+ @GET("/api/v2.1/collections")
+ fun getCollections(@Query("lat") lat: String,
+ @Query("lon") lon: String) : Observable
+
+ @GET("/api/v2.1/cities")
+ fun getCity(@Query("lat") lat: String,
+ @Query("lon") lon: String) : Observable
+
+ @GET("/api/v2.1/cuisines")
+ fun getCuisines(@Query("lat") lat: String,
+ @Query("lon") lon: String) : Observable
+
+ @GET("/api/v2.1/establishments")
+ fun getEstablishments(@Query("lat") lat: String,
+ @Query("lon") lon: String) : Observable
+
+ @GET("/api/v2.1/search")
+ fun searchByCollectionId(@Query("lat") lat: String,
+ @Query("lon") lon: String,
+ @Query("collection_id") collectionId: Int) : Observable
+
+ @GET("/api/v2.1/search")
+ fun searchByCategoryId(@Query("lat") lat: String,
+ @Query("lon") lon: String,
+ @Query("category") category: Int) : Observable
+
+ @GET("/api/v2.1/search")
+ fun searchByCuisineId(@Query("lat") lat: String,
+ @Query("lon") lon: String,
+ @Query("cuisines") cuisines: String) : Observable
+
+ @GET("/api/v2.1/search")
+ fun search(@Query("lat") lat: String,
+ @Query("lon") lon: String,
+ @Query("q") query: String) : Observable
+
+ @GET("/api/v2.1/restaurant")
+ fun getRestaurantDetails(@Query("res_id") resId: Int) : Observable
+
+ @GET("/api/v2.1/reviews")
+ fun getReviews(@Query("res_id") resId: Int) : Observable
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/Categories.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/Categories.kt
new file mode 100644
index 0000000..8933bfb
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/Categories.kt
@@ -0,0 +1,5 @@
+package com.soumya.wwdablu.hungry.network.model.categories
+
+import com.google.gson.annotations.SerializedName
+
+data class Categories(@SerializedName("categories") val category: Category)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/CategoriesModel.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/CategoriesModel.kt
new file mode 100644
index 0000000..7eed9ff
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/CategoriesModel.kt
@@ -0,0 +1,3 @@
+package com.soumya.wwdablu.hungry.network.model.categories
+
+data class CategoriesModel(val categories: List)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/Category.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/Category.kt
new file mode 100644
index 0000000..6b629b1
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/categories/Category.kt
@@ -0,0 +1,6 @@
+package com.soumya.wwdablu.hungry.network.model.categories
+
+import com.google.gson.annotations.SerializedName
+
+data class Category(@SerializedName("id") val id: Int,
+ @SerializedName("name") val name: String)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cities/City.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cities/City.kt
new file mode 100644
index 0000000..95e942a
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cities/City.kt
@@ -0,0 +1,32 @@
+package com.soumya.wwdablu.hungry.network.model.cities
+
+import com.google.gson.annotations.SerializedName
+
+data class City(
+ @SerializedName("id")
+ val id: String,
+
+ @SerializedName("name")
+ val name: String,
+
+ @SerializedName("country_id")
+ val countryId: String,
+
+ @SerializedName("country_name")
+ val countryName: String,
+
+ @SerializedName("is_state")
+ val isState: Int,
+
+ @SerializedName("state_id")
+ val stateId: String,
+
+ @SerializedName("state_name")
+ val stateName: String,
+
+ @SerializedName("state_code")
+ val stateCode: String,
+
+ @SerializedName("country_flag_url")
+ val countryFlagUrl: String
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cities/CityModel.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cities/CityModel.kt
new file mode 100644
index 0000000..0c9d4c3
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cities/CityModel.kt
@@ -0,0 +1,12 @@
+package com.soumya.wwdablu.hungry.network.model.cities
+
+import com.google.gson.annotations.SerializedName
+
+data class CityModel(
+
+ @SerializedName("location_suggestions")
+ val model: List,
+
+ @SerializedName("status")
+ val status: String
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CollectionInfo.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CollectionInfo.kt
new file mode 100644
index 0000000..93a3e34
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CollectionInfo.kt
@@ -0,0 +1,29 @@
+package com.soumya.wwdablu.hungry.network.model.collections
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class CollectionInfo(
+ @SerializedName("collection_id")
+ val id: String,
+
+ @SerializedName("title")
+ val title: String,
+
+ @SerializedName("url")
+ val url: String,
+
+ @SerializedName("description")
+ val description: String,
+
+ @SerializedName("image_url")
+ val imageUrl: String,
+
+ @SerializedName("res_count")
+ val count: String,
+
+ @SerializedName("share_url")
+ val shareUrl: String
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CollectionModel.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CollectionModel.kt
new file mode 100644
index 0000000..bdb9972
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CollectionModel.kt
@@ -0,0 +1,8 @@
+package com.soumya.wwdablu.hungry.network.model.collections
+
+import com.google.gson.annotations.SerializedName
+
+data class CollectionModel(
+ @SerializedName("collections")
+ val list: List
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CuratedCollection.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CuratedCollection.kt
new file mode 100644
index 0000000..e3e61d5
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/collections/CuratedCollection.kt
@@ -0,0 +1,8 @@
+package com.soumya.wwdablu.hungry.network.model.collections
+
+import com.google.gson.annotations.SerializedName
+
+data class CuratedCollection(
+ @SerializedName("collection")
+ val collection: CollectionInfo
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/Cuisine.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/Cuisine.kt
new file mode 100644
index 0000000..cf4319b
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/Cuisine.kt
@@ -0,0 +1,11 @@
+package com.soumya.wwdablu.hungry.network.model.cuisine
+
+import com.google.gson.annotations.SerializedName
+
+data class Cuisine(
+ @SerializedName("cuisine_id")
+ val cuisineId: String,
+
+ @SerializedName("cuisine_name")
+ val cuisineName: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/CuisineModel.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/CuisineModel.kt
new file mode 100644
index 0000000..f679f29
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/CuisineModel.kt
@@ -0,0 +1,8 @@
+package com.soumya.wwdablu.hungry.network.model.cuisine
+
+import com.google.gson.annotations.SerializedName
+
+data class CuisineModel(
+ @SerializedName("cuisines")
+ val list: List
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/CuisineObject.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/CuisineObject.kt
new file mode 100644
index 0000000..903b779
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/cuisine/CuisineObject.kt
@@ -0,0 +1,3 @@
+package com.soumya.wwdablu.hungry.network.model.cuisine
+
+data class CuisineObject(val cuisine: Cuisine)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/Establishment.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/Establishment.kt
new file mode 100644
index 0000000..46b2d82
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/Establishment.kt
@@ -0,0 +1,11 @@
+package com.soumya.wwdablu.hungry.network.model.establishments
+
+import com.google.gson.annotations.SerializedName
+
+data class Establishment(
+ @SerializedName("id")
+ val id: Int,
+
+ @SerializedName("name")
+ val name: String
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/EstablishmentModel.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/EstablishmentModel.kt
new file mode 100644
index 0000000..5c8284d
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/EstablishmentModel.kt
@@ -0,0 +1,9 @@
+package com.soumya.wwdablu.hungry.network.model.establishments
+
+import com.google.gson.annotations.SerializedName
+
+data class EstablishmentModel(
+
+ @SerializedName("establishments")
+ val list: List
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/EstablishmentObject.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/EstablishmentObject.kt
new file mode 100644
index 0000000..013b4ac
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/establishments/EstablishmentObject.kt
@@ -0,0 +1,8 @@
+package com.soumya.wwdablu.hungry.network.model.establishments
+
+import com.google.gson.annotations.SerializedName
+
+data class EstablishmentObject(
+ @SerializedName("establishment")
+ val establishment: Establishment
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/Review.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/Review.kt
new file mode 100644
index 0000000..381850a
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/Review.kt
@@ -0,0 +1,33 @@
+package com.soumya.wwdablu.hungry.network.model.reviews
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class Review (
+
+ val rating: Float,
+
+ @SerializedName("review_text")
+ val reviewText: String,
+
+ val id: Int,
+
+ @SerializedName("rating_color")
+ val ratingColor: String,
+
+ @SerializedName("review_time_friendly")
+ val reviewTimeFriendly: String,
+
+ @SerializedName("rating_text")
+ val ratingText: String,
+
+ val timestamp: Int,
+ val likes: Int,
+ val user: User,
+
+ @SerializedName("comments_count")
+ val commentsCount: Int
+
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/ReviewModel.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/ReviewModel.kt
new file mode 100644
index 0000000..71813ce
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/ReviewModel.kt
@@ -0,0 +1,16 @@
+package com.soumya.wwdablu.hungry.network.model.reviews
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+import kotlinx.parcelize.RawValue
+
+@Parcelize
+data class ReviewModel(
+
+ @SerializedName("reviews_count")
+ var reviewsCount: Int,
+
+ @SerializedName("user_reviews")
+ var reviewList: @RawValue List
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/User.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/User.kt
new file mode 100644
index 0000000..7979571
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/User.kt
@@ -0,0 +1,32 @@
+package com.soumya.wwdablu.hungry.network.model.reviews
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class User (
+ val name: String,
+
+ @SerializedName("zomato_handle")
+ val zomatoHandle: String,
+
+ @SerializedName("foodie_color")
+ val foodieColor: String,
+
+ @SerializedName("profile_url")
+ val profileUrl: String,
+
+ @SerializedName("profile_image")
+ val profileImage: String,
+
+ @SerializedName("profile_deeplink")
+ val profileDeeplink: String,
+
+ @SerializedName("foodie_level")
+ val foodieLevel: String,
+
+ @SerializedName("foodie_level_num")
+ val foodieLevelNum: Int
+
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/UserReview.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/UserReview.kt
new file mode 100644
index 0000000..c50d009
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/reviews/UserReview.kt
@@ -0,0 +1,5 @@
+package com.soumya.wwdablu.hungry.network.model.reviews
+
+data class UserReview(
+ val review: Review
+)
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/BgColor.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/BgColor.kt
new file mode 100644
index 0000000..928b600
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/BgColor.kt
@@ -0,0 +1,11 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class BgColor(
+ val type: String,
+ val tint: String
+
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/HasMenuStatus.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/HasMenuStatus.kt
new file mode 100644
index 0000000..176f02c
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/HasMenuStatus.kt
@@ -0,0 +1,17 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+import kotlinx.android.parcel.RawValue
+
+@Parcelize
+data class HasMenuStatus(
+
+ @SerializedName("delivery")
+ val delivery: @RawValue Any,
+
+ @SerializedName("takeaway")
+ val takeAway: Int
+
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Location.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Location.kt
new file mode 100644
index 0000000..17f4138
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Location.kt
@@ -0,0 +1,26 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class Location(
+ var address: String,
+ var locality: String,
+ var city: String,
+
+ @SerializedName("city_id")
+ var cityId: Int,
+
+ var latitude: String,
+ var longitude: String,
+ var zipcode: String,
+
+ @SerializedName("country_id")
+ var countryId: Int,
+
+ @SerializedName("locality_verbose")
+ var localityVerbose: String
+
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/R.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/R.kt
new file mode 100644
index 0000000..ed4246a
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/R.kt
@@ -0,0 +1,18 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class R(
+ @SerializedName("res_id")
+ val resId: Int,
+
+ @SerializedName("is_grocery_store")
+ val isGroceryStore: Boolean,
+
+ @SerializedName("has_menu_status")
+ val hasMenuStatus: HasMenuStatus
+
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/RatingObj.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/RatingObj.kt
new file mode 100644
index 0000000..4555251
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/RatingObj.kt
@@ -0,0 +1,14 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class RatingObj (
+ var title: Title,
+
+ @SerializedName("bg_color")
+ var bgColor: BgColor
+
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Restaurant.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Restaurant.kt
new file mode 100644
index 0000000..1cf7f9f
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Restaurant.kt
@@ -0,0 +1,11 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class Restaurant(
+ @SerializedName("restaurant")
+ val restaurant: RestaurantInfo
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/RestaurantInfo.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/RestaurantInfo.kt
new file mode 100644
index 0000000..2b69983
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/RestaurantInfo.kt
@@ -0,0 +1,95 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+import kotlin.math.roundToInt
+
+@Parcelize
+data class RestaurantInfo(
+
+ @SerializedName("R")
+ var r: R,
+ var apikey: String,
+ var id: String,
+ var name: String,
+ var url: String,
+ var location: Location,
+
+ @SerializedName("switch_to_order_menu")
+ var switchToOrderMenu: Int,
+
+ var cuisines: String,
+ var timings: String,
+
+ @SerializedName("average_cost_for_two")
+ var averageCostForTwo: Int,
+
+ @SerializedName("price_range")
+ var priceRange: Int,
+
+ var currency: String,
+ var highlights: List,
+
+ @SerializedName("is_zomato_book_res")
+ var isZomatoBookRes: Int,
+
+ @SerializedName("is_book_form_web_view")
+ var isBookFormWebView: Int,
+
+ @SerializedName("book_form_web_view_url")
+ var bookFormWebViewUrl: String,
+
+ @SerializedName("book_again_url")
+ var bookAgainUrl: String,
+
+ var thumb: String,
+
+ @SerializedName("user_rating")
+ var userRating: UserRating,
+
+ @SerializedName("all_reviews_count")
+ var allReviewsCount: Int,
+
+ @SerializedName("photos_url")
+ var photosUrl: String,
+
+ @SerializedName("photo_count")
+ var photoCount: Int,
+
+ @SerializedName("menu_url")
+ var menuUrl: String,
+
+ @SerializedName("featured_image")
+ var featuredImage: String,
+
+ @SerializedName("has_online_delivery")
+ var hasOnlineDelivery: Int,
+
+ @SerializedName("is_delivering_now")
+ var isDeliveringNow: Int,
+
+ @SerializedName("phone_numbers")
+ var phoneNumbers: String,
+
+ var establishment: List
+
+) : Parcelable {
+ companion object {
+ fun calculateDistance(fromLat: String, fromLon: String,
+ toLat: String, toLon: String) : String {
+
+ val from: android.location.Location = android.location.Location("from")
+ val to: android.location.Location = android.location.Location("from")
+
+ from.latitude = fromLat.toDouble()
+ from.longitude = fromLon.toDouble()
+
+ to.latitude = toLat.toDouble()
+ to.longitude = toLon.toDouble()
+
+ val distance: Float = from.distanceTo(to)
+ return "${(distance/1000).roundToInt()}"
+ }
+ }
+}
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/SearchModel.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/SearchModel.kt
new file mode 100644
index 0000000..1af3707
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/SearchModel.kt
@@ -0,0 +1,21 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class SearchModel(
+ @SerializedName("results_found")
+ val resultsFound: Int,
+
+ @SerializedName("results_start")
+ val resultsStart: Int,
+
+ @SerializedName("results_shown")
+ val resultsShown: Int,
+
+ @SerializedName("restaurants")
+ val restaurants: List
+
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Title.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Title.kt
new file mode 100644
index 0000000..13fa929
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/Title.kt
@@ -0,0 +1,10 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class Title(
+ val text: String
+
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/UserRating.kt b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/UserRating.kt
new file mode 100644
index 0000000..e381828
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/network/model/search/UserRating.kt
@@ -0,0 +1,24 @@
+package com.soumya.wwdablu.hungry.network.model.search
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class UserRating (
+
+ @SerializedName("aggregate_rating")
+ var aggregateRating: String,
+
+ @SerializedName("rating_text")
+ var ratingText: String,
+
+ @SerializedName("rating_color")
+ var ratingColor: String,
+
+ @SerializedName("rating_obj")
+ var ratingObj: RatingObj,
+
+ var votes: Int
+
+) : Parcelable
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/repository/HungryRepo.kt b/app/src/main/java/com/soumya/wwdablu/hungry/repository/HungryRepo.kt
new file mode 100644
index 0000000..27d17af
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/repository/HungryRepo.kt
@@ -0,0 +1,314 @@
+package com.soumya.wwdablu.hungry.repository
+
+import com.soumya.wwdablu.hungry.defines.CategoryEnum
+import com.soumya.wwdablu.hungry.network.model.categories.Categories
+import com.soumya.wwdablu.hungry.network.model.categories.CategoriesModel
+import com.soumya.wwdablu.hungry.network.model.cities.City
+import com.soumya.wwdablu.hungry.network.model.cities.CityModel
+import com.soumya.wwdablu.hungry.network.model.collections.CollectionModel
+import com.soumya.wwdablu.hungry.network.model.collections.CuratedCollection
+import com.soumya.wwdablu.hungry.network.model.cuisine.Cuisine
+import com.soumya.wwdablu.hungry.network.model.cuisine.CuisineModel
+import com.soumya.wwdablu.hungry.network.model.establishments.Establishment
+import com.soumya.wwdablu.hungry.network.model.establishments.EstablishmentModel
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import com.soumya.wwdablu.hungry.network.model.search.SearchModel
+import com.soumya.wwdablu.hungry.network.DataProvider
+import com.soumya.wwdablu.hungry.network.model.reviews.ReviewModel
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.core.Observable
+import io.reactivex.rxjava3.core.ObservableEmitter
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import java.util.*
+
+internal object HungryRepo {
+
+ private lateinit var mLocation: Pair
+
+ private lateinit var mCategoriesModel: CategoriesModel
+ private lateinit var mCollectionModel: CollectionModel
+ private lateinit var mCityModel: CityModel
+ private lateinit var mCuisineModel: CuisineModel
+ private lateinit var mEstablishmentModel: EstablishmentModel
+
+ fun getCityModel() : CityModel {
+ return mCityModel
+ }
+
+ fun setLocation(lat: String, lon: String) {
+ mLocation = Pair(lat, lon)
+ }
+
+ fun getLocation(): Pair {
+ return mLocation
+ }
+
+ fun getCategories() : Observable> {
+
+ return Observable.create {
+
+ if(this::mCategoriesModel.isInitialized && mCategoriesModel.categories.isNotEmpty()) {
+ it.onNext(mCategoriesModel.categories)
+ it.onComplete()
+ return@create
+ }
+
+ DataProvider.call().getCategories()
+ .observeOn(Schedulers.io())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: CategoriesModel?) {
+ mCategoriesModel = t ?: CategoriesModel(LinkedList())
+ it.onNext(LinkedList(mCategoriesModel.categories))
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e)
+ }
+
+ override fun onComplete() {
+ it.onComplete()
+ }
+ })
+ }
+ }
+
+ fun getCity() : Observable> {
+
+ return Observable.create {
+
+ if(this::mCityModel.isInitialized && mCityModel.model.isEmpty()) {
+ it.onNext(mCityModel.model)
+ it.onComplete()
+ return@create
+ }
+
+ DataProvider.call().getCity(mLocation.first, mLocation.second)
+ .observeOn(Schedulers.io())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: CityModel?) {
+ mCityModel = t ?: CityModel(LinkedList(), "success")
+ it.onNext(LinkedList(mCityModel.model))
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e)
+ }
+
+ override fun onComplete() {
+ it.onComplete()
+ }
+ })
+ }
+ }
+
+ fun getCollections() : Observable> {
+
+ return Observable.create {
+
+ if(this::mCollectionModel.isInitialized && mCollectionModel.list.isEmpty()) {
+ it.onNext(mCollectionModel.list)
+ it.onComplete()
+ return@create
+ }
+
+ DataProvider.call().getCollections(mLocation.first, mLocation.second)
+ .observeOn(Schedulers.io())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: CollectionModel?) {
+ mCollectionModel = t ?: CollectionModel(LinkedList())
+ it.onNext(LinkedList(mCollectionModel.list))
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e)
+ }
+
+ override fun onComplete() {
+ it.onComplete()
+ }
+ })
+ }
+ }
+
+ fun getCuisine() : Observable> {
+
+ return Observable.create {
+
+ if(this::mCuisineModel.isInitialized && mCuisineModel.list.isEmpty()) {
+ val listCuisine: LinkedList = LinkedList()
+ mCuisineModel.list.forEach { me ->
+ listCuisine.add(me.cuisine)
+ }
+ it.onNext(listCuisine)
+ it.onComplete()
+ return@create
+ }
+
+ DataProvider.call().getCuisines(mLocation.first, mLocation.second)
+ .observeOn(Schedulers.io())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: CuisineModel?) {
+ mCuisineModel = t ?: CuisineModel(LinkedList())
+ val listCuisine: LinkedList = LinkedList()
+ mCuisineModel.list.forEach { me ->
+ listCuisine.add(me.cuisine)
+ }
+ it.onNext(listCuisine)
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e)
+ }
+
+ override fun onComplete() {
+ it.onComplete()
+ }
+ })
+ }
+ }
+
+ fun getEstablishments() : Observable> {
+
+ return Observable.create {
+
+ if(this::mEstablishmentModel.isInitialized && mEstablishmentModel.list.isEmpty()) {
+ val listEstablishment: LinkedList = LinkedList()
+ mEstablishmentModel.list.forEach { me ->
+ listEstablishment.add(me.establishment)
+ }
+ it.onNext(listEstablishment)
+ it.onComplete()
+ return@create
+ }
+
+ DataProvider.call().getEstablishments(mLocation.first, mLocation.second)
+ .observeOn(Schedulers.io())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: EstablishmentModel?) {
+ mEstablishmentModel = t ?: EstablishmentModel(LinkedList())
+ val listEstablishment: LinkedList = LinkedList()
+ mEstablishmentModel.list.forEach { me ->
+ listEstablishment.add(me.establishment)
+ }
+ it.onNext(listEstablishment)
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e)
+ }
+
+ override fun onComplete() {
+ it.onComplete()
+ }
+ })
+ }
+ }
+
+ fun getRestaurantDetails(resId: Int) : Observable {
+
+ return Observable.create {
+
+ DataProvider.call().getRestaurantDetails(resId)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: RestaurantInfo?) {
+ it.onNext(t)
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e)
+ }
+
+ override fun onComplete() {
+ it.onComplete()
+ }
+ })
+ }
+ }
+
+ fun getReviews(resId: Int) : Observable {
+
+ return Observable.create {
+
+ DataProvider.call().getReviews(resId)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: ReviewModel?) {
+ it.onNext(t ?: ReviewModel(0, LinkedList()))
+ }
+
+ override fun onError(e: Throwable?) {
+ it.onError(e)
+ }
+
+ override fun onComplete() {
+ it.onComplete()
+ }
+ })
+ }
+ }
+
+ fun searchByCollectionId(collectionId: Int) : Observable {
+
+ return Observable.create {
+
+ handleSearchObservable(DataProvider.call().searchByCollectionId(
+ mLocation.first, mLocation.second, collectionId), it)
+ }
+ }
+
+ fun searchByCategoryId(category: CategoryEnum) : Observable {
+
+ return Observable.create {
+
+ handleSearchObservable(DataProvider.call().searchByCategoryId(
+ mLocation.first, mLocation.second, category.ordinal), it)
+ }
+ }
+
+ fun searchByCuisineId(cuisineId: String) : Observable {
+
+ return Observable.create {
+
+ handleSearchObservable(DataProvider.call().searchByCuisineId(
+ mLocation.first, mLocation.second, cuisineId), it)
+ }
+ }
+
+ fun search(query: String) : Observable {
+
+ return Observable.create {
+
+ handleSearchObservable(DataProvider.call().search(
+ mLocation.first, mLocation.second, query), it)
+ }
+ }
+
+ private fun handleSearchObservable(observable: Observable,
+ emitter: ObservableEmitter) {
+
+ observable.observeOn(Schedulers.io())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object : DisposableObserver() {
+ override fun onNext(t: SearchModel?) {
+ emitter.onNext(t)
+ }
+
+ override fun onError(e: Throwable?) {
+ emitter.onError(e)
+ }
+
+ override fun onComplete() {
+ emitter.onComplete()
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/hungry/utils/RestaurantInfoUtil.kt b/app/src/main/java/com/soumya/wwdablu/hungry/utils/RestaurantInfoUtil.kt
new file mode 100644
index 0000000..e45f85a
--- /dev/null
+++ b/app/src/main/java/com/soumya/wwdablu/hungry/utils/RestaurantInfoUtil.kt
@@ -0,0 +1,124 @@
+package com.soumya.wwdablu.hungry.utils
+
+import android.widget.ImageView
+import androidx.appcompat.widget.AppCompatImageView
+import com.bumptech.glide.Glide
+import com.soumya.wwdablu.hungry.R
+import com.soumya.wwdablu.hungry.network.model.search.RestaurantInfo
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
+import io.reactivex.rxjava3.core.Observable
+import io.reactivex.rxjava3.core.ObservableOnSubscribe
+import io.reactivex.rxjava3.observers.DisposableObserver
+import io.reactivex.rxjava3.schedulers.Schedulers
+import java.io.BufferedReader
+import java.io.InputStreamReader
+import java.net.URL
+import java.util.*
+
+object RestaurantInfoUtil {
+
+ /**
+ * Tries to set the image for the restaurant. It has few fallback methods. It tries for the
+ * provided feature image, then thumbnail. If both are absent then tries to get the
+ * photos. If that too fails, then default image is displayed. The entire process is both
+ * time and bandwidth consuming.
+ *
+ * @param userPhotoIfFeatureAbsent Set to false to prevent fetching user submitted photos
+ */
+ fun loadFeatureImage(imageView: AppCompatImageView, restaurant: RestaurantInfo,
+ userPhotoIfFeatureAbsent: Boolean = true) {
+
+ val imageUrl: String = if (restaurant.featuredImage.isNotEmpty() && restaurant.featuredImage.isNotBlank()) {
+ restaurant.featuredImage
+ } else {
+ restaurant.thumb
+ }
+
+ if(imageUrl.isNotBlank() && imageUrl.isNotEmpty()) {
+ loadImageIntoView(imageUrl, imageView)
+ }
+
+ else if(!userPhotoIfFeatureAbsent) {
+ imageView.setImageResource(R.drawable.default_card_bg)
+ return
+ }
+
+ else {
+ getPhotos(restaurant)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribeOn(Schedulers.io())
+ .subscribeWith(object: DisposableObserver>() {
+ override fun onNext(t: List?) {
+
+ if(t == null || t.isEmpty()) {
+ imageView.setImageResource(R.drawable.default_card_bg)
+ return
+ }
+
+ loadImageIntoView(t[0], imageView)
+ }
+
+ override fun onError(e: Throwable?) {
+ imageView.setImageResource(R.drawable.default_card_bg)
+ }
+
+ override fun onComplete() {
+ //
+ }
+ })
+ }
+ }
+
+ private fun loadImageIntoView(imageUrl: String, imageView: ImageView) {
+
+ Glide.with(imageView.context)
+ .load(imageUrl)
+ .placeholder(R.drawable.default_card_bg)
+ .into(imageView)
+ }
+
+ fun getPhotos(restaurant: RestaurantInfo) : Observable> {
+
+ return Observable.create(ObservableOnSubscribe> {
+
+ val photoList: LinkedList = LinkedList()
+ val photoUrl: String = restaurant.photosUrl
+
+ if (photoUrl.isEmpty() || photoUrl.isBlank()) {
+ it.onNext(photoList)
+ it.onComplete()
+ return@ObservableOnSubscribe
+ }
+
+ extractPhotoUrls(photoUrl, photoList)
+
+ it.onNext(photoList)
+ it.onComplete()
+
+ }).subscribeOn(Schedulers.io())
+ }
+
+ private fun extractPhotoUrls(photoUrl: String, possibleImageUrl: LinkedList) {
+
+ val url: URL = URL(photoUrl)
+ val streamReader = BufferedReader(InputStreamReader(url.openStream()))
+
+ var readLine: String? = streamReader.readLine()
+ while(readLine != null) {
+
+ val colonSplit = readLine.split(":\\\"")
+ if(colonSplit.isNotEmpty()) {
+ colonSplit.forEach { me ->
+ if (me.contains("https") && me.contains(".jpg\\\"")) {
+ val iUrl = me.substring(0, me.indexOf(".jpg\\\"") + 4)
+ possibleImageUrl.add(iUrl)
+ }
+ }
+ }
+
+ readLine = streamReader.readLine()
+ }
+
+ streamReader.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/DashboardActivity.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/DashboardActivity.java
deleted file mode 100644
index 81616a8..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/DashboardActivity.java
+++ /dev/null
@@ -1,152 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.activity;
-
-import android.content.Intent;
-import android.databinding.DataBindingUtil;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.support.design.widget.TabLayout;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v7.app.AppCompatActivity;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.common.Analytics;
-import com.soumya.wwdablu.zomatobuddy.common.SearchTypes;
-import com.soumya.wwdablu.zomatobuddy.database.CacheDB;
-import com.soumya.wwdablu.zomatobuddy.databinding.ActivityDashboardBinding;
-import com.soumya.wwdablu.zomatobuddy.fragment.CategoryList;
-import com.soumya.wwdablu.zomatobuddy.fragment.IRestaurantAction;
-import com.soumya.wwdablu.zomatobuddy.model.LocationCoordinates;
-import com.soumya.wwdablu.zomatobuddy.model.categories.CategoryResponse;
-import com.soumya.wwdablu.zomatobuddy.model.search.Restaurant;
-import com.soumya.wwdablu.zomatobuddy.viewadapter.DashboardPageAdapter;
-
-import org.parceler.Parcels;
-
-import java.util.ArrayList;
-
-import timber.log.Timber;
-
-public class DashboardActivity extends AppCompatActivity implements IRestaurantAction {
-
- private static final int MAX_TABS = 4;
-
- private ActivityDashboardBinding dashboardBinder;
- private LocationCoordinates locationCoordinates;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
-
- super.onCreate(savedInstanceState);
- dashboardBinder = DataBindingUtil.setContentView(this, R.layout.activity_dashboard);
-
- //Fetch the data received from the splash screen
- locationCoordinates = Parcels.unwrap(getIntent().getBundleExtra("data").getParcelable("location"));
- CategoryResponse categoryResponse = Parcels.unwrap(getIntent().getBundleExtra("data").getParcelable("categoryResponse"));
-
- //Set the toolbar
- setSupportActionBar(dashboardBinder.toolbar);
-
- //Create the state pager adapter
- FragmentStatePagerAdapter fragmentStatePagerAdapter = new DashboardPageAdapter(getSupportFragmentManager(),
- locationCoordinates, MAX_TABS, getTabHeaderInfos(), this);
-
- // Set up the ViewPager with the state pager adapter.
- dashboardBinder.container.setAdapter(fragmentStatePagerAdapter);
-
- dashboardBinder.container.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(dashboardBinder.tabs));
- dashboardBinder.tabs.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(dashboardBinder.container));
-
- dashboardBinder.tabs.setSelectedTabIndicatorColor(Color.YELLOW);
-
- //Analytics information
- Analytics.setAnalyiticsFor("DemoUser");
- Analytics.setCurrentScreen(this, "Dashboard");
- Analytics.setUserAction(Analytics.EVENT_APP_START, Analytics.PARAM_APP_START, "DemoUser");
- }
-
-
- @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_dashboard, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
-
- switch(item.getItemId()) {
-
- case R.id.menu_source_search:
- launchSearchActivity();
- break;
-
- default:
- return super.onOptionsItemSelected(item);
- }
-
- return true;
- }
-
- @Override
- public void onBackPressed() {
- CacheDB.getInstance().purgeCache();
- super.onBackPressed();
- }
-
- @Override
- public void onClick(Restaurant restaurant) {
-
- launchNextActivity(restaurant);
- }
-
- private void launchNextActivity(Restaurant restaurant) {
- Timber.d(restaurant.getName());
- Intent launchIntent = new Intent(this, RestaurantDetailsActivity.class);
- launchIntent.putExtra("resid", restaurant.getId());
- launchIntent.putExtra("rName", restaurant.getName());
- launchIntent.putExtra("rCuisine", restaurant.getCuisines());
- startActivity(launchIntent);
- }
-
- private void launchSearchActivity() {
-
- Timber.d("Launching search activity");
- Intent searchIntent = new Intent(this, SearchActivity.class);
- searchIntent.putExtra("location", Parcels.wrap(locationCoordinates));
- startActivity(searchIntent);
- }
-
- private ArrayList getTabHeaderInfos() {
-
- ArrayList pageInfos = new ArrayList<>(MAX_TABS);
-
- pageInfos.add(new DashboardPageAdapter.PageInfo(
- "Go out for lunch or dinner",
- "Dine-out restaurants",
- SearchTypes.SEARCH_DINE_OUT
- ));
-
- pageInfos.add(new DashboardPageAdapter.PageInfo(
- "Get food delivered",
- "Delivery restaurants",
- SearchTypes.SEARCH_DELIVERY
- ));
-
- pageInfos.add(new DashboardPageAdapter.PageInfo(
- "Grab food to-go",
- "Delivery restaurants",
- SearchTypes.SEARCH_TAKE_AWAY
- ));
-
- pageInfos.add(new DashboardPageAdapter.PageInfo(
- "Favourites",
- "Favourite restaurants",
- SearchTypes.SEARCH_FAVOURITE
- ));
-
- return pageInfos;
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/RestaurantDetailsActivity.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/RestaurantDetailsActivity.java
deleted file mode 100644
index 1edb956..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/RestaurantDetailsActivity.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.activity;
-
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.common.Analytics;
-import com.soumya.wwdablu.zomatobuddy.fragment.RestaurantDetails;
-
-public class RestaurantDetailsActivity extends AppCompatActivity {
-
- private static final String FTAG_DETAILS = "detailsFragment";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_restaurant_details);
-
- Bundle bundle = new Bundle();
- bundle.putString("resid", getIntent().getStringExtra("resid"));
- bundle.putString("rName", getIntent().getStringExtra("rName"));
- bundle.putString("rCuisine", getIntent().getStringExtra("rCuisine"));
-
- RestaurantDetails fragment = new RestaurantDetails();
- fragment.setArguments(bundle);
- getSupportFragmentManager().beginTransaction()
- .add(R.id.fl_rest_details_activity_container, fragment, FTAG_DETAILS)
- .commit();
-
- //Analytics information
- Analytics.setCurrentScreen(this, "Restaurant Details");
- Analytics.setUserAction(Analytics.EVENT_RESTAURANT_DETAILS, Analytics.PARAM_RESTAURANT_SELECTED,
- getIntent().getStringExtra("rName"));
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/SearchActivity.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/SearchActivity.java
deleted file mode 100644
index f965761..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/SearchActivity.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.activity;
-
-import android.content.Intent;
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.common.Analytics;
-import com.soumya.wwdablu.zomatobuddy.fragment.Search;
-import com.soumya.wwdablu.zomatobuddy.model.search.Restaurant;
-
-import timber.log.Timber;
-
-public class SearchActivity extends AppCompatActivity implements Search.ISearchAcion {
-
- private static final String FTAG_SEARCH_FRAGMENT = "fragmentSearch";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_search);
-
- Search fragment = (Search) getSupportFragmentManager().findFragmentByTag(FTAG_SEARCH_FRAGMENT);
-
- if(null == fragment) {
-
- fragment = new Search();
-
- Bundle bundle = new Bundle();
- bundle.putParcelable("location", getIntent().getParcelableExtra("location"));
- fragment.setArguments(bundle);
-
- getSupportFragmentManager().beginTransaction()
- .add(R.id.fl_search_activity, fragment, FTAG_SEARCH_FRAGMENT)
- .commit();
- }
-
- fragment.setSearchAction(this);
-
- //Analytics information
- Analytics.setCurrentScreen(this, "Search Activity");
- }
-
- @Override
- public void onRestaurantSelected(Restaurant restaurant) {
-
- Timber.d(restaurant.getName());
- Intent launchIntent = new Intent(this, RestaurantDetailsActivity.class);
- launchIntent.putExtra("resid", restaurant.getId());
- launchIntent.putExtra("rName", restaurant.getName());
- launchIntent.putExtra("rCuisine", restaurant.getCuisines());
- startActivity(launchIntent);
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/SplashActivity.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/SplashActivity.java
deleted file mode 100644
index 99bdc53..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/activity/SplashActivity.java
+++ /dev/null
@@ -1,212 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.activity;
-
-import android.Manifest;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.location.Location;
-import android.os.Bundle;
-import android.os.Looper;
-import android.support.annotation.NonNull;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.app.AppCompatActivity;
-
-import com.google.android.gms.location.FusedLocationProviderClient;
-import com.google.android.gms.location.LocationCallback;
-import com.google.android.gms.location.LocationRequest;
-import com.google.android.gms.location.LocationResult;
-import com.google.android.gms.location.LocationServices;
-import com.soumya.wwdablu.zomatobuddy.BuildConfig;
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.dagger.DaggerNetworkComponent;
-import com.soumya.wwdablu.zomatobuddy.dagger.NetworkModule;
-import com.soumya.wwdablu.zomatobuddy.model.LocationCoordinates;
-import com.soumya.wwdablu.zomatobuddy.model.categories.CategoryResponse;
-import com.soumya.wwdablu.zomatobuddy.network.ZomatoServiceApi;
-
-import org.parceler.Parcels;
-
-import javax.inject.Inject;
-
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.observers.DisposableObserver;
-import io.reactivex.schedulers.Schedulers;
-import timber.log.Timber;
-
-public class SplashActivity extends AppCompatActivity {
-
- private static final int LOCATION_REQUEST_CODE = 1001;
-
- @Inject
- ZomatoServiceApi zomatoServiceApi;
-
- private DisposableObserver disposableObserver;
- private CategoryResponse categoryResponse;
- private Location location;
- private FusedLocationProviderClient locationProviderClient;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_splash);
-
- DaggerNetworkComponent.builder()
- .networkModule(new NetworkModule(BuildConfig.ZOMATO_BASE_URL))
- .build()
- .inject(this);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- confirmUserAction();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (null != disposableObserver && !disposableObserver.isDisposed()) {
- disposableObserver.dispose();
- }
-
- if(null != locationProviderClient) {
- locationProviderClient.removeLocationUpdates(locationCallback);
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-
- switch (requestCode) {
-
- case LOCATION_REQUEST_CODE:
- if (PackageManager.PERMISSION_GRANTED == grantResults[0]) {
- fetchLocationInformation();
- } else {
- location = null;
- fetchDataFromZomatoToProceed();
- }
- break;
-
- default:
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }
- }
-
- private void requestLocationAccess() {
-
- //If the permission has been provided
- if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_FINE_LOCATION)) {
-
- fetchLocationInformation();
- return;
- }
-
- //Request the permission from the user
- ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
- LOCATION_REQUEST_CODE);
- }
-
- private void fetchLocationInformation() {
-
- //Guard check
- if (ActivityCompat.checkSelfPermission(SplashActivity.this,
- Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
- return;
- }
-
- locationProviderClient = LocationServices.getFusedLocationProviderClient(getApplicationContext());
-
- //Listen for the last location from the provider
- locationProviderClient.getLastLocation()
- .addOnSuccessListener(loc -> {
-
- //We did not get the last location, lets get it
- if(null == loc) {
-
- LocationRequest locationRequest = LocationRequest.create()
- .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
- .setInterval(10000)
- .setFastestInterval(1000);
-
- locationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
-
- } else {
- location = loc;
- fetchDataFromZomatoToProceed();
- }
- })
- .addOnFailureListener(e -> {
- location = null;
- fetchDataFromZomatoToProceed();
- });
- }
-
- private LocationCallback locationCallback = new LocationCallback() {
-
- @Override
- public void onLocationResult(LocationResult locationResult) {
- super.onLocationResult(locationResult);
- location = locationResult.getLastLocation();
- locationProviderClient.removeLocationUpdates(locationCallback);
- fetchDataFromZomatoToProceed();
- }
- };
-
- private void fetchDataFromZomatoToProceed() {
-
- disposableObserver = zomatoServiceApi.getCategories()
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(CategoryResponse catRes) {
- categoryResponse = catRes;
- Timber.d("The category has been received: %s", categoryResponse.getCategories().size());
- }
-
- @Override
- public void onError(Throwable e) {
- finish();
- }
-
- @Override
- public void onComplete() {
- launchNextScreen();
- }
- });
- }
-
- private void launchNextScreen() {
-
- LocationCoordinates locationCoordinates = new LocationCoordinates();
- locationCoordinates.setLongitude(null == location ? Double.parseDouble(BuildConfig.DEFAULT_LOGITUDE)
- : location.getLongitude());
-
- locationCoordinates.setLatitude(null == location ? Double.parseDouble(BuildConfig.DEFAULT_LATITUDE)
- : location.getLatitude());
-
- Bundle bundle = new Bundle();
- bundle.putParcelable("categoryResponse", Parcels.wrap(categoryResponse));
- bundle.putParcelable("location", Parcels.wrap(locationCoordinates));
-
- Intent dashboardIntent = new Intent(this, DashboardActivity.class);
- dashboardIntent.putExtra("data", bundle);
-
- startActivity(dashboardIntent);
- finish();
- }
-
- private void confirmUserAction() {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle("ATTENTION")
- .setMessage(R.string.notify_user)
- .setPositiveButton("I Agree", (dialogInterface, i) -> requestLocationAccess())
- .setNegativeButton("Exit", (dialogInterface, i) -> finish())
- .setCancelable(false);
- builder.create().show();
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/Analytics.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/Analytics.java
deleted file mode 100644
index 3bf210c..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/Analytics.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.common;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringDef;
-
-import com.google.firebase.analytics.FirebaseAnalytics;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-public class Analytics {
-
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({
- EVENT_APP_START,
- EVENT_DETAILS_ITEM,
- EVENT_RESTAURANT_DETAILS,
- EVENT_SEARCH
- })
- public @interface EventType{}
-
- public static final String EVENT_SEARCH = FirebaseAnalytics.Event.SEARCH;
- public static final String EVENT_RESTAURANT_DETAILS = FirebaseAnalytics.Event.VIEW_ITEM_LIST;
- public static final String EVENT_DETAILS_ITEM = FirebaseAnalytics.Event.SELECT_CONTENT;
- public static final String EVENT_APP_START = FirebaseAnalytics.Event.APP_OPEN;
-
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({
- PARAM_APP_START,
- PARAM_DETAIL_ITEM_SELECTED,
- PARAM_RESTAURANT_SELECTED,
- PARAM_SEARCH_TERM
- })
- public @interface ParamType{}
-
- public static final String PARAM_SEARCH_TERM = FirebaseAnalytics.Param.SEARCH_TERM;
- public static final String PARAM_RESTAURANT_SELECTED = FirebaseAnalytics.Param.ORIGIN;
- public static final String PARAM_DETAIL_ITEM_SELECTED = FirebaseAnalytics.Param.SOURCE;
- public static final String PARAM_APP_START = "ZBuddyUser";
-
- private static FirebaseAnalytics analytics;
-
- public static void init(Context context) {
-
- if(null == analytics) {
- analytics = FirebaseAnalytics.getInstance(context);
- analytics.setAnalyticsCollectionEnabled(true);
- analytics.setMinimumSessionDuration(5000);
- analytics.setSessionTimeoutDuration(30000);
- }
- }
-
- public static void setAnalyiticsFor(String user) {
- analytics.setUserId(user);
- }
-
- public static void setCurrentScreen(@NonNull Activity activity, @NonNull String screenName) {
- analytics.setCurrentScreen(activity, screenName, null);
- }
-
- public static void setUserAction(@NonNull @EventType String event, @NonNull @ParamType String param, String data) {
-
- Bundle bundle = new Bundle();
- bundle.putString(param, data);
- analytics.logEvent(event, bundle);
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/DefaultCuisineImage.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/DefaultCuisineImage.java
deleted file mode 100644
index f7094e8..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/DefaultCuisineImage.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.common;
-
-import android.support.annotation.DrawableRes;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-
-import java.util.HashMap;
-
-public class DefaultCuisineImage {
-
- private static HashMap cuisineDefaultCardImage;
- static {
- initCuisineDefaultCardImage();
- }
-
- public static synchronized @DrawableRes int getCuisineImage(String cuisine) {
-
- @DrawableRes int drawableRes;
-
- if(cuisineDefaultCardImage.containsKey(cuisine.toLowerCase())) {
- drawableRes = cuisineDefaultCardImage.get(cuisine.toLowerCase());
- } else {
- drawableRes = cuisineDefaultCardImage.get("default");
- }
-
- return drawableRes;
- }
-
- private static void initCuisineDefaultCardImage() {
-
- if(null == cuisineDefaultCardImage) {
- cuisineDefaultCardImage = new HashMap<>();
- }
-
- //No need to insert, already its done
- if(0 != cuisineDefaultCardImage.size()) {
- return;
- }
-
- cuisineDefaultCardImage.put("indian", R.drawable.default_food_indian);
- cuisineDefaultCardImage.put("mexican", R.drawable.default_food_mexican);
- cuisineDefaultCardImage.put("american", R.drawable.default_food_american);
- cuisineDefaultCardImage.put("chinese", R.drawable.default_food_chinese);
- cuisineDefaultCardImage.put("italian", R.drawable.default_food_italian);
- cuisineDefaultCardImage.put("japanese", R.drawable.default_food_japanese);
- cuisineDefaultCardImage.put("default", R.drawable.default_food);
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/SearchTypes.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/SearchTypes.java
deleted file mode 100644
index 42f91d3..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/common/SearchTypes.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.common;
-
-import android.support.annotation.StringDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-public class SearchTypes {
-
- @Retention(RetentionPolicy.SOURCE)
- @StringDef({
- SEARCH_DINE_OUT,
- SEARCH_DELIVERY,
- SEARCH_TAKE_AWAY,
- SEARCH_FAVOURITE
- })
- public @interface SearchType{}
-
- public static final String SEARCH_DINE_OUT = "2";
- public static final String SEARCH_DELIVERY = "1";
- public static final String SEARCH_TAKE_AWAY = "5";
- public static final String SEARCH_FAVOURITE = "999";
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/dagger/NetworkComponent.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/dagger/NetworkComponent.java
deleted file mode 100644
index 05e8613..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/dagger/NetworkComponent.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.dagger;
-
-import com.soumya.wwdablu.zomatobuddy.activity.DashboardActivity;
-import com.soumya.wwdablu.zomatobuddy.activity.SplashActivity;
-import com.soumya.wwdablu.zomatobuddy.model.RestaurantDetailsModel;
-import com.soumya.wwdablu.zomatobuddy.model.RestaurantListModel;
-import com.soumya.wwdablu.zomatobuddy.model.ReviewModel;
-import com.soumya.wwdablu.zomatobuddy.model.SearchModel;
-
-import javax.inject.Singleton;
-
-import dagger.Component;
-
-@Component(modules = NetworkModule.class)
-@Singleton
-public interface NetworkComponent {
-
- void inject(SplashActivity splashActivity);
- void inject(DashboardActivity dashboardActivity);
-
- void inject(RestaurantListModel restaurantListModel);
- void inject(RestaurantDetailsModel restaurantDetailsModel);
- void inject(ReviewModel reviewModel);
- void inject(SearchModel searchModel);
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/dagger/NetworkModule.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/dagger/NetworkModule.java
deleted file mode 100644
index 661ad9a..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/dagger/NetworkModule.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.dagger;
-
-import com.soumya.wwdablu.zomatobuddy.BuildConfig;
-import com.soumya.wwdablu.zomatobuddy.network.ZomatoServiceApi;
-
-import javax.inject.Singleton;
-
-import dagger.Module;
-import dagger.Provides;
-import okhttp3.Interceptor;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.logging.HttpLoggingInterceptor;
-import retrofit2.Retrofit;
-import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
-import retrofit2.converter.gson.GsonConverterFactory;
-import retrofit2.converter.scalars.ScalarsConverterFactory;
-
-@Module
-public class NetworkModule {
-
- private String baseUrl;
-
- public NetworkModule(String baseUrl) {
- this.baseUrl = baseUrl;
- }
-
- @Singleton
- @Provides
- public ZomatoServiceApi provideZomatoServiceApi() {
-
- return provideRetrofit().create(ZomatoServiceApi.class);
- }
-
- @Singleton
- @Provides
- public Retrofit provideRetrofit() {
-
- return new Retrofit.Builder()
- .baseUrl(baseUrl)
- .client(provideOkHttpClient())
- .addConverterFactory(provideGsonConverterFactory())
- .addCallAdapterFactory(provideRxCallAdapterFactory())
- .build();
- }
-
- @Singleton
- @Provides
- public GsonConverterFactory provideGsonConverterFactory() {
- return GsonConverterFactory.create();
- }
-
- @Singleton
- @Provides
- public ScalarsConverterFactory provideScalarConverterFactory() {
- return ScalarsConverterFactory.create();
- }
-
- @Singleton
- @Provides
- public RxJava2CallAdapterFactory provideRxCallAdapterFactory() {
- return RxJava2CallAdapterFactory.create();
- }
-
- @Singleton
- @Provides
- public OkHttpClient provideOkHttpClient() {
-
- return new OkHttpClient.Builder()
- .addInterceptor(provideInterceptor())
- .addInterceptor(provideHttpLogginInterceptor())
- .build();
- }
-
- @Singleton
- @Provides
- public Interceptor provideInterceptor() {
-
- return chain -> {
-
- Request modifiedRequest = chain.request().newBuilder()
- .addHeader("user-key", BuildConfig.ZOMATO_API_KEY)
- .build();
-
- return chain.proceed(modifiedRequest);
- };
- }
-
- @Singleton
- @Provides
- public HttpLoggingInterceptor provideHttpLogginInterceptor() {
-
- HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
- loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
-
- return loggingInterceptor;
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/database/CacheDB.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/database/CacheDB.java
deleted file mode 100644
index 30c2e97..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/database/CacheDB.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.database;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-public class CacheDB extends SQLiteOpenHelper {
-
- private static final String DB_NAME = "response_cache";
- private static final int DB_VERSION = 1;
-
- private static CacheDB instance;
-
- private CacheDB(Context context) {
- super(context, DB_NAME, null, DB_VERSION);
- }
-
- public static synchronized void init(Context context) {
-
- if(null == instance) {
- instance = new CacheDB(context);
- }
- }
-
- public static synchronized CacheDB getInstance() {
- return instance;
- }
-
- @Override
- public void onCreate(SQLiteDatabase sqLiteDatabase) {
-
- sqLiteDatabase.execSQL(
- "CREATE TABLE " + DatabaseContract.ResponseCache.TABLE + " (" +
- DatabaseContract.ResponseCache.CATEGORY_ID + " TEXT PRIMARY KEY, " +
- DatabaseContract.ResponseCache.RESPONSE + " TEXT " +
- ");"
- );
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
- //
- }
-
- public synchronized void cache(String id, String response) {
-
- SQLiteDatabase db = getWritableDatabase();
-
- Cursor cursor = db.query(DatabaseContract.ResponseCache.TABLE, null,
- DatabaseContract.ResponseCache.CATEGORY_ID + "=?", new String[] {id}, null,
- null, null);
-
- if(null != cursor && cursor.moveToFirst()) {
-
- ContentValues contentValues = new ContentValues();
- contentValues.put(DatabaseContract.ResponseCache.RESPONSE, response);
-
- db.update(DatabaseContract.ResponseCache.TABLE, contentValues, DatabaseContract.ResponseCache.CATEGORY_ID + "=?",
- new String[] {id});
-
- } else {
-
- ContentValues contentValues = new ContentValues();
- contentValues.put(DatabaseContract.ResponseCache.CATEGORY_ID, id);
- contentValues.put(DatabaseContract.ResponseCache.RESPONSE, response);
-
- db.insert(DatabaseContract.ResponseCache.TABLE, null, contentValues);
- }
-
- if(null != cursor) {
- cursor.close();
- }
-
- db.close();
- }
-
- public synchronized String getFromCache(String id) {
-
- SQLiteDatabase db = getReadableDatabase();
-
- Cursor cursor = db.query(DatabaseContract.ResponseCache.TABLE, null,
- DatabaseContract.ResponseCache.CATEGORY_ID + "=?", new String[] {id}, null,
- null, null);
-
- String responseData = "";
- if(null != cursor && cursor.moveToFirst()) {
-
- responseData = cursor.getString(cursor.getColumnIndex(DatabaseContract.ResponseCache.RESPONSE));
- }
-
- if(null != cursor) {
- cursor.close();
- }
-
- db.close();
- return responseData;
- }
-
- public synchronized void purgeCache() {
-
- SQLiteDatabase db = getWritableDatabase();
- db.delete(DatabaseContract.ResponseCache.TABLE, null, null);
- db.close();
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/database/DatabaseContract.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/database/DatabaseContract.java
deleted file mode 100644
index 9771fe9..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/database/DatabaseContract.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.database;
-
-public final class DatabaseContract {
-
- public static final class ResponseCache {
- public static final String TABLE = "responseCacheTable";
- public static final String CATEGORY_ID = "categoryId";
- public static final String RESPONSE = "response";
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/CategoryList.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/CategoryList.java
deleted file mode 100644
index ec25c9e..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/CategoryList.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.fragment;
-
-import android.databinding.DataBindingUtil;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v7.widget.GridLayoutManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.common.SearchTypes;
-import com.soumya.wwdablu.zomatobuddy.databinding.FragmentCategorylistBinding;
-import com.soumya.wwdablu.zomatobuddy.model.search.Restaurant;
-import com.soumya.wwdablu.zomatobuddy.model.search.SearchResponse;
-import com.soumya.wwdablu.zomatobuddy.viewadapter.CategoryRecyclerAdapter;
-import com.soumya.wwdablu.zomatobuddy.viewmodel.CategoryViewModel;
-
-import org.parceler.Parcels;
-
-public class CategoryList extends Fragment implements CategoryViewModel.ISearchResult,
- IRestaurantAction {
-
- public static final String KEY_HEADER_TITLE = "headerTitle";
- public static final String KEY_HEADER_SUB_TITLE = "headerSubTitle";
- public static final String KEY_LOCATION_COORDINATE = "locationCoordinate";
- public static final @SearchTypes.SearchType String KEY_SEARCH_TYPE = "searchType";
-
- private FragmentCategorylistBinding categorylistBinder;
- private CategoryRecyclerAdapter categoryRecyclerAdapter;
- private IRestaurantAction restaurantActionImpl;
-
- private CategoryViewModel categoryViewModel;
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-
- categoryViewModel = new CategoryViewModel(getArguments().getString(KEY_SEARCH_TYPE),
- Parcels.unwrap(getArguments().getParcelable(KEY_LOCATION_COORDINATE)), this);
-
- categorylistBinder = DataBindingUtil.inflate(inflater, R.layout.fragment_categorylist,
- container, false);
-
- //Set the header titles
- categoryViewModel.setHeaderTitle(getArguments().getString(KEY_HEADER_TITLE));
- categoryViewModel.setHeaderSubTitle(getArguments().getString(KEY_HEADER_SUB_TITLE));
-
- //Setup the recycler view
- categoryRecyclerAdapter = new CategoryRecyclerAdapter(this);
- categoryRecyclerAdapter.setHasStableIds(true);
- categorylistBinder.rvCategoryRestaurants.setLayoutManager(new GridLayoutManager(getActivity(), 2));
- categorylistBinder.rvCategoryRestaurants.addItemDecoration(
- new CategoryRecyclerAdapter.CardDecorator(getActivity(), R.dimen.card_margins));
- categorylistBinder.rvCategoryRestaurants.setAdapter(categoryRecyclerAdapter);
-
- return categorylistBinder.getRoot();
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- }
-
- @Override
- public void onSearchComplete(SearchResponse searchResponse) {
- categorylistBinder.setCatViewModel(categoryViewModel);
- categoryRecyclerAdapter.setSearchResponse(searchResponse);
- }
-
- public void setRestaurantAction(IRestaurantAction action) {
- this.restaurantActionImpl = action;
- }
-
- @Override
- public void onClick(Restaurant restaurant) {
-
- if(null == restaurantActionImpl) {
- return;
- }
-
- restaurantActionImpl.onClick(restaurant);
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/FavouriteList.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/FavouriteList.java
deleted file mode 100644
index 2f098d7..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/FavouriteList.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.fragment;
-
-import android.databinding.DataBindingUtil;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v7.widget.GridLayoutManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.common.SearchTypes;
-import com.soumya.wwdablu.zomatobuddy.databinding.FragmentFavlistBinding;
-import com.soumya.wwdablu.zomatobuddy.model.search.Restaurant;
-import com.soumya.wwdablu.zomatobuddy.viewadapter.FavouritesRecyclerAdapter;
-import com.soumya.wwdablu.zomatobuddy.viewmodel.FavouritesViewModel;
-
-public class FavouriteList extends Fragment implements IRestaurantAction {
-
- public static final String KEY_HEADER_TITLE = "headerTitle";
- public static final String KEY_HEADER_SUB_TITLE = "headerSubTitle";
-
- //This will always be favourite and is not dynamic
- private static final @SearchTypes.SearchType String KEY_SEARCH_TYPE = SearchTypes.SEARCH_FAVOURITE;
-
- private FragmentFavlistBinding binder;
- private FavouritesRecyclerAdapter adapter;
- private IRestaurantAction favRestaurantImpl;
-
- private FavouritesViewModel favouritesViewModel;
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-
- favouritesViewModel = new FavouritesViewModel();
-
- binder = DataBindingUtil.inflate(inflater, R.layout.fragment_favlist,
- container, false);
-
- adapter = new FavouritesRecyclerAdapter();
- binder.rvFavRestaurants.setLayoutManager(new GridLayoutManager(getActivity(), 2));
- binder.rvFavRestaurants.addItemDecoration(
- new FavouritesRecyclerAdapter.CardDecorator(getActivity(), R.dimen.card_margins));
-
- //Set the view model for the view binding
- binder.setFavViewModel(favouritesViewModel);
-
- //Set the header titles
- favouritesViewModel.setHeaderTitle(getArguments().getString(KEY_HEADER_TITLE));
- favouritesViewModel.setHeaderSubTitle(getArguments().getString(KEY_HEADER_SUB_TITLE));
-
- return binder.getRoot();
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
-
- binder.rvFavRestaurants.setAdapter(adapter);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- //Set the view model for the adapter
- adapter.setFavouriteDataList(favouritesViewModel);
- adapter.setRestaurantAction(this);
- }
-
- @Override
- public void onClick(Restaurant restaurant) {
-
- if(null == favRestaurantImpl) {
- return;
- }
-
- favRestaurantImpl.onClick(restaurant);
- }
-
- public void setRestaurantAction(IRestaurantAction action) {
- this.favRestaurantImpl = action;
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/IRestaurantAction.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/IRestaurantAction.java
deleted file mode 100644
index 9dcf13a..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/IRestaurantAction.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.fragment;
-
-import com.soumya.wwdablu.zomatobuddy.model.search.Restaurant;
-
-public interface IRestaurantAction {
- void onClick(Restaurant restaurant);
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/RestaurantDetails.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/RestaurantDetails.java
deleted file mode 100644
index a6f3518..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/RestaurantDetails.java
+++ /dev/null
@@ -1,275 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.fragment;
-
-import android.content.Intent;
-import android.databinding.DataBindingUtil;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.design.widget.AppBarLayout;
-import android.support.v4.app.Fragment;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Toast;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.common.DefaultCuisineImage;
-import com.soumya.wwdablu.zomatobuddy.databinding.FragmentRestaurantDetailsBinding;
-import com.soumya.wwdablu.zomatobuddy.model.Favourites;
-import com.soumya.wwdablu.zomatobuddy.model.favourite.FavouriteData;
-import com.soumya.wwdablu.zomatobuddy.viewadapter.ItemsAdapter;
-import com.soumya.wwdablu.zomatobuddy.viewadapter.ReviewAdapter;
-import com.soumya.wwdablu.zomatobuddy.viewmodel.RestaurantDetailsViewModel;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-
-public class RestaurantDetails extends Fragment implements RestaurantDetailsViewModel.IDetailsAction,
- ItemsAdapter.IIteamAction {
-
- private FragmentRestaurantDetailsBinding binder;
- private RestaurantDetailsViewModel restaurantDetailsViewModel;
- private ItemsAdapter adapter;
- private ReviewAdapter reviewAdapter;
-
- private String restaurantName;
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-
- binder = DataBindingUtil.inflate(inflater, R.layout.fragment_restaurant_details,
- container, false);
-
- //Get the name of the restaurant from the caller
- restaurantName = getArguments().getString("rName");
-
- String cuisine = getArguments().getString("rCuisine");
- cuisine = cuisine.split(",")[0];
- binder.ivRestDetailsHeader.setImageDrawable(ContextCompat.getDrawable(binder.ivRestDetailsHeader.getContext(),
- DefaultCuisineImage.getCuisineImage(cuisine)));
-
- restaurantDetailsViewModel = new RestaurantDetailsViewModel(this);
- binder.cardLayoutRestDetailsHeader.setRestDetails(restaurantDetailsViewModel);
-
- ((AppCompatActivity) getActivity()).setSupportActionBar(binder.toolbarRestDetails);
-
- binder.ablRestDetails.addOnOffsetChangedListener(offsetChangeListener);
-
- //Restaurant Details
- binder.rvRestDetailsActions.setLayoutManager(new StaggeredGridLayoutManager(2,
- StaggeredGridLayoutManager.VERTICAL));
- binder.rvRestDetailsActions.addItemDecoration(new ItemsAdapter.ItemDecorate(getActivity(), R.dimen.card_margins));
-
- adapter = new ItemsAdapter(restaurantDetailsViewModel, this);
- binder.rvRestDetailsActions.setAdapter(adapter);
-
- //Restaurant Reviews
- binder.rvReviewList.setLayoutManager(new LinearLayoutManager(getActivity()));
-
- //This has option menu
- setHasOptionsMenu(true);
-
- return binder.getRoot();
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- fetchRestaurantDetails();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- reviewAdapter.clean();
- restaurantDetailsViewModel.clean();
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- inflater.inflate(R.menu.menu_rest_details, menu);
- super.onCreateOptionsMenu(menu, inflater);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
-
- switch (item.getItemId()) {
-
- case R.id.menu_share:
- showShareOptionMenu();
- break;
-
- case R.id.menu_fav:
-
- if(restaurantDetailsViewModel.isFavouriteRestaurant()) {
-
- restaurantDetailsViewModel.removeFavourite(restaurantDetailsViewModel
- .getRestaurantId(), callbackStatus);
-
- } else {
-
- restaurantDetailsViewModel.addFavourite(restaurantDetailsViewModel.getRestaurantId(),
- restaurantDetailsViewModel.getRestaurantName().get(),
- restaurantDetailsViewModel.getRestaurantLocation().get(),
- restaurantDetailsViewModel.getRestaurantCuisines().get(),
- callbackStatus);
- }
- break;
-
- default:
- return super.onOptionsItemSelected(item);
- }
-
- return true;
- }
-
- @Override
- public void onSuccess() {
-
- //Display the information
- adapter.bindData(getItems());
-
- binder.mergePb.pbRestDetailsProgress.setVisibility(View.GONE);
- binder.ablRestDetails.setVisibility(View.VISIBLE);
- binder.nsvRestDetailsContainer.setVisibility(View.VISIBLE);
-
- //Now get and display the review information
- reviewAdapter = new ReviewAdapter(getArguments().getString("resid"));
- binder.rvReviewList.setAdapter(reviewAdapter);
-
- //Mark, if the restaurant is already a favourite
- if(restaurantDetailsViewModel.isFavouriteRestaurant()) {
- binder.toolbarRestDetails.getMenu().findItem(R.id.menu_fav).setIcon(R.drawable.ic_heart);
- }
- }
-
- @Override
- public void onError() {
- handleErrorResponse();
- }
-
- @Override
- public void onClick(int position) {
-
- Intent viewIntent = new Intent(Intent.ACTION_VIEW);
-
- switch(position) {
- case 0:
- viewIntent.setData(Uri.parse(restaurantDetailsViewModel.getMenuUrl()));
- break;
-
- case 1:
- viewIntent.setData(Uri.parse(restaurantDetailsViewModel.getPhotoUrl()));
- break;
-
- case 2:
- viewIntent.setData(Uri.parse(restaurantDetailsViewModel.getWebsiteUrl()));
- break;
-
- case 3:
- viewIntent.setData(Uri.parse(restaurantDetailsViewModel.getZomatoDeepLink()));
- break;
- }
-
- //Resolve and launch the intent
- if(null != viewIntent.resolveActivity(getActivity().getPackageManager())) {
- startActivity(viewIntent);
- }
- }
-
- private AppBarLayout.OnOffsetChangedListener offsetChangeListener = new AppBarLayout.OnOffsetChangedListener() {
-
- boolean isShow = false;
- int scrollRange = -1;
- int visibleRange = 0;
-
- @Override
- public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
-
- if (scrollRange == -1) {
- scrollRange = appBarLayout.getTotalScrollRange();
- visibleRange = scrollRange / 4;
- }
-
- if(scrollRange + verticalOffset <= visibleRange && !isShow) {
-
- binder.ctRestDetails.setTitle(restaurantName);
- isShow = true;
- binder.toolbarRestDetails.getMenu().findItem(R.id.menu_share).setVisible(true);
- binder.toolbarRestDetails.getMenu().findItem(R.id.menu_fav).setVisible(true);
-
- } else if(scrollRange + verticalOffset > visibleRange && isShow) {
-
- binder.ctRestDetails.setTitle(" ");
- isShow = false;
- binder.toolbarRestDetails.getMenu().findItem(R.id.menu_share).setVisible(false);
- binder.toolbarRestDetails.getMenu().findItem(R.id.menu_fav).setVisible(false);
- }
- }
- };
-
- private void fetchRestaurantDetails() {
-
- String s = getArguments().getString("resid");
- restaurantDetailsViewModel.getRestaurantDetails(s);
- }
-
- private void handleErrorResponse() {
-
- Toast.makeText(getActivity(), R.string.could_not_fetch_generic,
- Toast.LENGTH_SHORT).show();
- }
-
- private ArrayList getItems() {
-
- ArrayList arrayList = new ArrayList<>(5);
- arrayList.add(new ItemsAdapter.ItemInfo("Menu", R.drawable.restaurant_menu));
- arrayList.add(new ItemsAdapter.ItemInfo("Photo", R.drawable.food_icon));
- arrayList.add(new ItemsAdapter.ItemInfo("Website", R.drawable.web_icon));
- arrayList.add(new ItemsAdapter.ItemInfo("Zomato App", R.drawable.link_icon));
-
- return arrayList;
- }
-
- private void showShareOptionMenu() {
-
- Intent shareIntent = new Intent(Intent.ACTION_SEND);
- shareIntent.putExtra(Intent.EXTRA_TEXT, restaurantDetailsViewModel.getWebsiteUrl());
- shareIntent.setType("text/plain");
- startActivity(Intent.createChooser(shareIntent, getString(R.string.share_rest_info)));
- }
-
- private Favourites.ITransactionStatus callbackStatus = new Favourites.ITransactionStatus() {
-
- @Override
- public void onSuccess(Favourites.FavAction action) {
-
- if(Favourites.FavAction.ADD == action) {
- Toast.makeText(getActivity(), R.string.rest_fav_marked, Toast.LENGTH_SHORT).show();
- binder.toolbarRestDetails.getMenu().findItem(R.id.menu_fav).setIcon(R.drawable.ic_heart);
- } else {
- Toast.makeText(getActivity(), R.string.rest_fav_unmarked, Toast.LENGTH_SHORT).show();
- binder.toolbarRestDetails.getMenu().findItem(R.id.menu_fav).setIcon(R.drawable.ic_heart_outline);
- }
- }
-
- @Override
- public void onError(Favourites.FavAction action) {
- Toast.makeText(getActivity(), R.string.rest_fav_cannot_marked, Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public void onFavListRetrieved(LinkedList favouriteDataList) {
- //Not applicable for this screen
- }
- };
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/Search.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/Search.java
deleted file mode 100644
index ac7e10c..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/fragment/Search.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.fragment;
-
-import android.databinding.DataBindingUtil;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.SearchView;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.soumya.wwdablu.zomatobuddy.R;
-import com.soumya.wwdablu.zomatobuddy.databinding.FragmentSearchBinding;
-import com.soumya.wwdablu.zomatobuddy.model.search.Restaurant;
-import com.soumya.wwdablu.zomatobuddy.viewadapter.SearchAdapter;
-
-import org.parceler.Parcels;
-
-import java.util.concurrent.TimeUnit;
-
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.observers.DisposableObserver;
-import io.reactivex.schedulers.Schedulers;
-import io.reactivex.subjects.PublishSubject;
-
-public class Search extends Fragment implements SearchAdapter.ISearchAction {
-
- public interface ISearchAcion {
- void onRestaurantSelected(Restaurant restaurant);
- }
-
- private FragmentSearchBinding binder;
- private SearchAdapter searchAdapter;
- public DisposableObserver disposableObserver;
- private ISearchAcion searchAcion;
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-
- searchAdapter = new SearchAdapter(Parcels.unwrap(getArguments().getParcelable("location")), this);
-
- binder = DataBindingUtil.inflate(inflater, R.layout.fragment_search, container, false);
-
- binder.rvSearchResult.setLayoutManager(new LinearLayoutManager(getActivity()));
- binder.rvSearchResult.setAdapter(searchAdapter);
-
- disposableObserver = new ReactSearch().getReactiveSearcher(binder.svSearchQuery)
- .debounce(1000, TimeUnit.MILLISECONDS)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(String searchString) {
-
- binder.tvSearchError.setVisibility(View.GONE);
- binder.rvSearchResult.setVisibility(View.GONE);
-
- if(!TextUtils.isEmpty(searchString)) {
- binder.pbSearch.setVisibility(View.VISIBLE);
- searchAdapter.search(searchString);
- } else {
- binder.pbSearch.setVisibility(View.GONE);
- searchAdapter.clearSearch();
- }
- }
-
- @Override
- public void onError(Throwable e) {
-
- }
-
- @Override
- public void onComplete() {
-
- }
- });
-
-
- return binder.getRoot();
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
-
- if(null != disposableObserver && !disposableObserver.isDisposed()) {
- disposableObserver.dispose();
- }
- }
-
- @Override
- public void onClick(Restaurant restaurant) {
-
- if(null != searchAcion) {
- searchAcion.onRestaurantSelected(restaurant);
- }
- }
-
- @Override
- public void onSearchComplete(int count) {
-
- if(0 == count) {
- binder.pbSearch.setVisibility(View.GONE);
- binder.tvSearchError.setVisibility(View.VISIBLE);
- binder.rvSearchResult.setVisibility(View.GONE);
- } else {
- binder.pbSearch.setVisibility(View.GONE);
- binder.tvSearchError.setVisibility(View.GONE);
- binder.rvSearchResult.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onSearchError() {
-
- binder.pbSearch.setVisibility(View.GONE);
- binder.tvSearchError.setVisibility(View.VISIBLE);
- binder.rvSearchResult.setVisibility(View.GONE);
- }
-
- public void setSearchAction(ISearchAcion searchAction) {
- this.searchAcion = searchAction;
- }
-
- private class ReactSearch {
-
- private PublishSubject subject;
-
- ReactSearch() {
- subject = PublishSubject.create();
- }
-
- PublishSubject getReactiveSearcher(final SearchView searchView) {
-
- searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- return true;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
-
- subject.onNext(newText);
- return true;
- }
- });
-
- return subject;
- }
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/Favourites.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/Favourites.java
deleted file mode 100644
index c20053d..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/Favourites.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model;
-
-import com.soumya.wwdablu.zomatobuddy.model.favourite.FavouriteData;
-
-import java.util.LinkedList;
-
-import io.reactivex.Observable;
-import io.reactivex.ObservableOnSubscribe;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.observers.DisposableObserver;
-import io.reactivex.schedulers.Schedulers;
-import io.realm.Realm;
-import io.realm.RealmResults;
-import timber.log.Timber;
-
-public class Favourites {
-
- public enum FavAction {
- ADD,
- REMOVE,
- LIST
- }
-
- public interface ITransactionStatus {
- void onSuccess(FavAction action);
- void onError(FavAction action);
- void onFavListRetrieved(LinkedList favouriteDataList);
- }
-
- public static void addFavourite(String resId, String resName, String resLocation, String resCuisines,
- ITransactionStatus callbackStatus) {
-
-
- Observable.create((ObservableOnSubscribe) emitter -> {
-
- try (Realm db = Realm.getDefaultInstance()) {
-
- db.executeTransaction(realm -> {
-
- FavouriteData data = realm.where(FavouriteData.class).equalTo("resId", resId).findFirst();
-
- //The data already exists
- if(null != data) {
-
- data.setResId(resId);
- data.setResName(resName);
- data.setResCuisines(resCuisines);
- data.setResLocation(resLocation);
-
- } else {
-
- Number id = realm.where(FavouriteData.class).max("id");
- FavouriteData newData = realm.createObject(FavouriteData.class, null == id ? 1 : id.intValue() + 1);
-
- newData.setResId(resId);
- newData.setResName(resName);
- newData.setResCuisines(resCuisines);
- newData.setResLocation(resLocation);
- }
-
- emitter.onNext(true);
- });
- }
- })
-
- .subscribeOn(Schedulers.computation())
- .observeOn(AndroidSchedulers.mainThread())
-
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(Boolean boolVal) {
- if(null != callbackStatus) {
- callbackStatus.onSuccess(FavAction.ADD);
- }
- }
-
- @Override
- public void onError(Throwable e) {
-
- Timber.e("Could not add to favourite. %s", e.getMessage());
-
- if(null != callbackStatus) {
- callbackStatus.onError(FavAction.ADD);
- }
- }
-
- @Override
- public void onComplete() {
- //
- }
- });
- }
-
- public static void removeFavourite(String resId, ITransactionStatus callbackStatus) {
-
- Observable.create((ObservableOnSubscribe) emitter -> {
-
- try (Realm db = Realm.getDefaultInstance()) {
-
- db.executeTransaction(realm -> {
-
- FavouriteData result = realm.where(FavouriteData.class).equalTo("resId", resId).findFirst();
-
- if(null != result) {
- result.deleteFromRealm();
- emitter.onNext(true);
- return;
- }
-
- emitter.onNext(false);
- });
- }
- })
-
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
-
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(Boolean aBoolean) {
-
- Timber.d("Removed from favourite: %s", aBoolean);
- if(null != callbackStatus) {
- callbackStatus.onSuccess(FavAction.REMOVE);
- }
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e("Error while removing from fav list. %s", e.getMessage());
- if(null != callbackStatus) {
- callbackStatus.onError(FavAction.REMOVE);
- }
- }
-
- @Override
- public void onComplete() {
- //
- }
- });
- }
-
- public static void getFavouriteDataList(ITransactionStatus callbackStatus) {
-
- Observable.create((ObservableOnSubscribe>) emitter -> {
-
- try (Realm db = Realm.getDefaultInstance()) {
-
- db.executeTransaction(realm -> {
-
- RealmResults result = realm.where(FavouriteData.class).findAll();
- LinkedList resultData = new LinkedList<>();
-
- for(FavouriteData data : result) {
- resultData.add(new FavouriteData(data));
- }
-
- emitter.onNext(resultData);
- });
- }
- })
-
- .subscribeOn(Schedulers.computation())
- .observeOn(AndroidSchedulers.mainThread())
-
- .subscribeWith(new DisposableObserver>() {
- @Override
- public void onNext(LinkedList dataList) {
-
- if(null != callbackStatus) {
- callbackStatus.onFavListRetrieved(dataList);
- }
- }
-
- @Override
- public void onError(Throwable e) {
-
- if(null != callbackStatus) {
- callbackStatus.onError(FavAction.LIST);
- }
- }
-
- @Override
- public void onComplete() {
- //
- }
- });
- }
-
- public static Observable isFavouriteRestaurant(final String resId) {
-
- return Observable.create(emitter -> {
-
- try (Realm db = Realm.getDefaultInstance()) {
-
- db.executeTransaction(realm -> {
-
- FavouriteData result = realm.where(FavouriteData.class).equalTo("resId", resId).findFirst();
-
- emitter.onNext(null != result);
- });
- }
- });
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/LocationCoordinates.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/LocationCoordinates.java
deleted file mode 100644
index 517526c..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/LocationCoordinates.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model;
-
-import org.parceler.Parcel;
-
-@Parcel
-public class LocationCoordinates {
-
- public double longitude;
- public double latitude;
-
- public double getLongitude() {
- return longitude;
- }
-
- public void setLongitude(double longitude) {
- this.longitude = longitude;
- }
-
- public double getLatitude() {
- return latitude;
- }
-
- public void setLatitude(double latitude) {
- this.latitude = latitude;
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/RestaurantDetailsModel.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/RestaurantDetailsModel.java
deleted file mode 100644
index 23eb115..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/RestaurantDetailsModel.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model;
-
-import com.soumya.wwdablu.zomatobuddy.dagger.DaggerNetworkComponent;
-import com.soumya.wwdablu.zomatobuddy.dagger.NetworkModule;
-import com.soumya.wwdablu.zomatobuddy.model.restaurant.RestaurantResponse;
-import com.soumya.wwdablu.zomatobuddy.network.ZomatoServiceApi;
-
-import javax.inject.Inject;
-
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.observers.DisposableObserver;
-import io.reactivex.schedulers.Schedulers;
-import timber.log.Timber;
-
-public class RestaurantDetailsModel {
-
- @Inject
- ZomatoServiceApi zomatoServiceApi;
-
- private DisposableObserver disposableObserver;
- private RestaurantResponse restaurantResponse;
-
- public RestaurantDetailsModel(String baseUrl) {
-
- DaggerNetworkComponent.builder()
- .networkModule(new NetworkModule(baseUrl))
- .build()
- .inject(this);
- }
-
- public Observable getRestaurantDetails(String resId) {
-
- return Observable.create(emitter -> {
-
- if (null != restaurantResponse) {
- emitter.onNext(restaurantResponse);
- emitter.onComplete();
- return;
- }
-
- disposableObserver = zomatoServiceApi.getRestaurantDetails(resId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(RestaurantResponse restaurantResponse) {
-
- RestaurantDetailsModel.this.restaurantResponse = restaurantResponse;
- emitter.onNext(restaurantResponse);
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e("Error while fetching restaurant details. %s", e.getMessage());
- emitter.onError(e);
- }
-
- @Override
- public void onComplete() {
- emitter.onComplete();
- }
- });
- });
- }
-
- public String getMenuUrl() {
- return restaurantResponse.getMenuUrl();
- }
-
- public String getPhotoUrl() {
- return restaurantResponse.getPhotosUrl();
- }
-
- public String getWebsite() {
- return restaurantResponse.getUrl();
- }
-
- public String getZomatoLink() {
- return restaurantResponse.getDeeplink();
- }
-
- public String getRestaurantId() {
- return restaurantResponse.getId();
- }
-
- public void clean() {
-
- if (null != disposableObserver && !disposableObserver.isDisposed()) {
- disposableObserver.dispose();
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/RestaurantListModel.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/RestaurantListModel.java
deleted file mode 100644
index 6c4dc7a..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/RestaurantListModel.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model;
-
-import com.google.gson.Gson;
-import com.soumya.wwdablu.zomatobuddy.BuildConfig;
-import com.soumya.wwdablu.zomatobuddy.common.SearchTypes;
-import com.soumya.wwdablu.zomatobuddy.dagger.DaggerNetworkComponent;
-import com.soumya.wwdablu.zomatobuddy.dagger.NetworkModule;
-import com.soumya.wwdablu.zomatobuddy.database.CacheDB;
-import com.soumya.wwdablu.zomatobuddy.model.search.SearchResponse;
-import com.soumya.wwdablu.zomatobuddy.network.ZomatoServiceApi;
-
-import javax.inject.Inject;
-
-import io.reactivex.Observable;
-import io.reactivex.ObservableOnSubscribe;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.observers.DisposableObserver;
-import io.reactivex.schedulers.Schedulers;
-import timber.log.Timber;
-
-public class RestaurantListModel {
-
- @Inject
- ZomatoServiceApi zomatoServiceApi;
-
- private @SearchTypes.SearchType String searchType;
- private DisposableObserver disposableObserver;
-
- public RestaurantListModel(@SearchTypes.SearchType String searchType) {
-
- this.searchType = searchType;
-
- DaggerNetworkComponent.builder()
- .networkModule(new NetworkModule(BuildConfig.ZOMATO_BASE_URL))
- .build()
- .inject(this);
- }
-
- /**
- * Performs a search on the location
- * @param locationCoordinates Provides the coordinate of the location
- * @return Observable which will be notified when the data is available
- */
- public Observable search(LocationCoordinates locationCoordinates) {
-
- //This returns the observable which will fire once an observer is subscribed with it
- return Observable.create(emitter ->
-
- disposableObserver = Observable.defer(() -> Observable.create((ObservableOnSubscribe) cacheEmitter -> {
-
- String data = CacheDB.getInstance().getFromCache(searchType);
- cacheEmitter.onNext(data);
-
- })).flatMap(responseCache -> {
-
- if(!"".equals(responseCache.trim())) {
- return Observable.just(new Gson().fromJson(responseCache, SearchResponse.class));
- }
-
- return zomatoServiceApi.getCategorySearch(Double.toString(locationCoordinates.getLatitude()),
- Double.toString(locationCoordinates.getLongitude()), searchType);
-
- }).subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(SearchResponse searchResponse) {
-
- cacheSearchResponse(searchResponse);
- emitter.onNext(searchResponse);
- }
-
- @Override
- public void onError(Throwable e) {
- emitter.onError(e);
- }
-
- @Override
- public void onComplete() {
- emitter.onComplete();
- clean();
- }
- }));
- }
-
- /**
- * Must call this method when the DataModel is no longer required.
- */
- public void clean() {
-
- if(null != disposableObserver && !disposableObserver.isDisposed()) {
- disposableObserver.dispose();
- }
- }
-
- private void cacheSearchResponse(SearchResponse searchResponse) {
-
- Observable.just(searchResponse)
- .subscribeOn(Schedulers.io())
- .observeOn(Schedulers.io())
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(SearchResponse response) {
- CacheDB.getInstance().cache(searchType, new Gson().toJson(searchResponse));
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e("Could not store the information in the cache for %s", searchType);
- }
-
- @Override
- public void onComplete() {
-
- }
- });
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/ReviewModel.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/ReviewModel.java
deleted file mode 100644
index c64c54e..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/ReviewModel.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model;
-
-import com.soumya.wwdablu.zomatobuddy.dagger.DaggerNetworkComponent;
-import com.soumya.wwdablu.zomatobuddy.dagger.NetworkModule;
-import com.soumya.wwdablu.zomatobuddy.model.reviews.ReviewResponse;
-import com.soumya.wwdablu.zomatobuddy.network.ZomatoServiceApi;
-
-import javax.inject.Inject;
-
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.observers.DisposableObserver;
-import io.reactivex.schedulers.Schedulers;
-import timber.log.Timber;
-
-public class ReviewModel {
-
- @Inject
- ZomatoServiceApi zomatoServiceApi;
-
- private ReviewResponse reviewReviewResponse;
- private DisposableObserver disposableObserver;
-
- public ReviewModel(String baseUrl) {
-
- //Instead of accessing BuildConfig, in here we are taking it as
- //an input from the constructor.
- DaggerNetworkComponent.builder()
- .networkModule(new NetworkModule(baseUrl))
- .build()
- .inject(this);
- }
-
- public Observable getReviews(String restaurantId) {
-
- return Observable.create(emitter -> {
-
- if(null != reviewReviewResponse) {
- emitter.onNext(reviewReviewResponse);
- emitter.onComplete();
- return;
- }
-
- disposableObserver = zomatoServiceApi.getReviews(restaurantId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver() {
- @Override
- public void onNext(ReviewResponse reviewReviewResponse) {
- ReviewModel.this.reviewReviewResponse = reviewReviewResponse;
- emitter.onNext(reviewReviewResponse);
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e("Error while getting review list. %s", e.getMessage());
- emitter.onError(e);
- }
-
- @Override
- public void onComplete() {
- emitter.onComplete();
- }
- });
- });
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/SearchModel.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/SearchModel.java
deleted file mode 100644
index 159a05c..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/SearchModel.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model;
-
-import com.soumya.wwdablu.zomatobuddy.common.Analytics;
-import com.soumya.wwdablu.zomatobuddy.dagger.DaggerNetworkComponent;
-import com.soumya.wwdablu.zomatobuddy.dagger.NetworkModule;
-import com.soumya.wwdablu.zomatobuddy.model.search.SearchResponse;
-import com.soumya.wwdablu.zomatobuddy.network.ZomatoServiceApi;
-
-import javax.inject.Inject;
-
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.observers.DisposableObserver;
-import io.reactivex.schedulers.Schedulers;
-import timber.log.Timber;
-
-public class SearchModel {
-
- @Inject
- ZomatoServiceApi zomatoServiceApi;
-
- private DisposableObserver disposableObserver;
- private LocationCoordinates locationCoordinates;
-
- public SearchModel(String baseUrl, LocationCoordinates locationCoordinates) {
-
- this.locationCoordinates = locationCoordinates;
-
- DaggerNetworkComponent.builder()
- .networkModule(new NetworkModule(baseUrl))
- .build()
- .inject(this);
- }
-
- public Observable search(String searchText) {
-
- if(null != disposableObserver && !disposableObserver.isDisposed()) {
- disposableObserver.dispose();
- }
-
- return Observable.create(emitter -> disposableObserver = zomatoServiceApi.getsearchResults(locationCoordinates.getLatitude(),
- locationCoordinates.getLongitude(), searchText, 20, 5000)
-
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableObserver() {
-
- @Override
- public void onNext(SearchResponse searchResponse) {
- emitter.onNext(searchResponse);
-
- //Analytics information
- Analytics.setUserAction(Analytics.EVENT_SEARCH, Analytics.PARAM_SEARCH_TERM,
- searchText);
- }
-
- @Override
- public void onError(Throwable e) {
- Timber.e("Error while searching for user query. %s", e.getMessage());
- emitter.onError(e);
- }
-
- @Override
- public void onComplete() {
- emitter.onComplete();
- }
- }));
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/Categories.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/Categories.java
deleted file mode 100644
index 20f6445..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/Categories.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model.categories;
-
-import org.parceler.Parcel;
-
-@Parcel
-public class Categories{
-
- public String name;
- public int id;
-
- public void setName(String name){
- this.name = name;
- }
-
- public String getName(){
- return name;
- }
-
- public void setId(int id){
- this.id = id;
- }
-
- public int getId(){
- return id;
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/CategoriesItem.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/CategoriesItem.java
deleted file mode 100644
index 5aac88d..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/CategoriesItem.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model.categories;
-
-import org.parceler.Parcel;
-
-@Parcel
-public class CategoriesItem{
-
- public Categories categories;
-
- public void setCategories(Categories categories){
- this.categories = categories;
- }
-
- public Categories getCategories(){
- return categories;
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/CategoryResponse.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/CategoryResponse.java
deleted file mode 100644
index ff8600b..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/categories/CategoryResponse.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model.categories;
-
-import org.parceler.Parcel;
-
-import java.util.List;
-
-@Parcel
-public class CategoryResponse {
-
- public List categories;
-
- public void setCategories(List categories){
- this.categories = categories;
- }
-
- public List getCategories(){
- return categories;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/favourite/FavouriteData.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/favourite/FavouriteData.java
deleted file mode 100644
index b4803e6..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/favourite/FavouriteData.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model.favourite;
-
-import io.realm.RealmObject;
-import io.realm.annotations.Index;
-import io.realm.annotations.PrimaryKey;
-
-public class FavouriteData extends RealmObject {
-
- @PrimaryKey
- long id;
-
- @Index
- private String resId;
-
- private String resName;
- private String resLocation;
- private String resCuisines;
-
- public FavouriteData() {
- super();
- }
-
- public FavouriteData(FavouriteData model) {
-
- this.id = model.id;
- this.resId = model.resId;
- this.resName = model.resName;
- this.resCuisines = model.resCuisines;
- this.resLocation = model.resLocation;
- }
-
- public long getId() {
- return id;
- }
-
- public void setId(long id) {
- this.id = id;
- }
-
- public String getResId() {
- return resId;
- }
-
- public void setResId(String resId) {
- this.resId = resId;
- }
-
- public String getResName() {
- return resName;
- }
-
- public void setResName(String resName) {
- this.resName = resName;
- }
-
- public String getResLocation() {
- return resLocation;
- }
-
- public void setResLocation(String resLocation) {
- this.resLocation = resLocation;
- }
-
- public String getResCuisines() {
- return resCuisines;
- }
-
- public void setResCuisines(String resCuisines) {
- this.resCuisines = resCuisines;
- }
-}
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/Location.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/Location.java
deleted file mode 100644
index 1affc53..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/Location.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model.restaurant;
-
-import com.google.gson.annotations.SerializedName;
-
-
-public class Location{
-
- @SerializedName("zipcode")
- private String zipcode;
-
- @SerializedName("address")
- private String address;
-
- @SerializedName("city")
- private String city;
-
- @SerializedName("locality_verbose")
- private String localityVerbose;
-
- @SerializedName("latitude")
- private String latitude;
-
- @SerializedName("locality")
- private String locality;
-
- @SerializedName("country_id")
- private int countryId;
-
- @SerializedName("city_id")
- private int cityId;
-
- @SerializedName("longitude")
- private String longitude;
-
- public void setZipcode(String zipcode){
- this.zipcode = zipcode;
- }
-
- public String getZipcode(){
- return zipcode;
- }
-
- public void setAddress(String address){
- this.address = address;
- }
-
- public String getAddress(){
- return address;
- }
-
- public void setCity(String city){
- this.city = city;
- }
-
- public String getCity(){
- return city;
- }
-
- public void setLocalityVerbose(String localityVerbose){
- this.localityVerbose = localityVerbose;
- }
-
- public String getLocalityVerbose(){
- return localityVerbose;
- }
-
- public void setLatitude(String latitude){
- this.latitude = latitude;
- }
-
- public String getLatitude(){
- return latitude;
- }
-
- public void setLocality(String locality){
- this.locality = locality;
- }
-
- public String getLocality(){
- return locality;
- }
-
- public void setCountryId(int countryId){
- this.countryId = countryId;
- }
-
- public int getCountryId(){
- return countryId;
- }
-
- public void setCityId(int cityId){
- this.cityId = cityId;
- }
-
- public int getCityId(){
- return cityId;
- }
-
- public void setLongitude(String longitude){
- this.longitude = longitude;
- }
-
- public String getLongitude(){
- return longitude;
- }
-
- @Override
- public String toString(){
- return
- "Location{" +
- "zipcode = '" + zipcode + '\'' +
- ",address = '" + address + '\'' +
- ",city = '" + city + '\'' +
- ",locality_verbose = '" + localityVerbose + '\'' +
- ",latitude = '" + latitude + '\'' +
- ",locality = '" + locality + '\'' +
- ",country_id = '" + countryId + '\'' +
- ",city_id = '" + cityId + '\'' +
- ",longitude = '" + longitude + '\'' +
- "}";
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/R.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/R.java
deleted file mode 100644
index 727889d..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/R.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model.restaurant;
-
-import com.google.gson.annotations.SerializedName;
-
-
-public class R{
-
- @SerializedName("res_id")
- private int resId;
-
- public void setResId(int resId){
- this.resId = resId;
- }
-
- public int getResId(){
- return resId;
- }
-
- @Override
- public String toString(){
- return
- "R{" +
- "res_id = '" + resId + '\'' +
- "}";
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/RestaurantResponse.java b/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/RestaurantResponse.java
deleted file mode 100644
index f137f34..0000000
--- a/app/src/main/java/com/soumya/wwdablu/zomatobuddy/model/restaurant/RestaurantResponse.java
+++ /dev/null
@@ -1,280 +0,0 @@
-package com.soumya.wwdablu.zomatobuddy.model.restaurant;
-
-import com.google.gson.annotations.SerializedName;
-
-import java.util.List;
-
-
-public class RestaurantResponse{
-
- @SerializedName("offers")
- private List