diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..27bdd2f --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +MVVMDemoWithDI \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..526b4c2 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..e6a8b91 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c26d7b5 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Doctor-Care-App diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..3de5d21 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,100 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'dagger.hilt.android.plugin' + id 'kotlin-kapt' + id 'com.google.gms.google-services' +} + +android { + compileSdk 31 + + defaultConfig { + applicationId "com.ketub4.mvvmdemowithdi" + minSdk 21 + targetSdk 31 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildFeatures { + viewBinding true + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + + } + +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation 'com.google.firebase:firebase-firestore-ktx:24.0.1' +// implementation 'com.firebaseui:firebase-ui-storage:7.2.0' +// implementation 'com.google.firebase:firebase-storage-ktx' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + + implementation("com.google.dagger:hilt-android:2.38.1") + kapt("com.google.dagger:hilt-android-compiler:2.38.1") + + + def lifecycle_version = "2.3.1" + def retorfit_version = '2.9.0' + + //coroutines + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9") + // ViewModel + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version") + // LiveData + implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version") + // Saved state module for ViewModel + implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version") + // Annotation processor + kapt("androidx.lifecycle:lifecycle-compiler:$lifecycle_version") + // alternately - if using Java8, use the following instead of lifecycle-compiler + implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycle_version") + implementation("androidx.activity:activity-ktx:1.2.3") + //glide + implementation 'com.github.bumptech.glide:glide:4.12.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' + + //retrofit + implementation "com.squareup.retrofit2:retrofit:$retorfit_version" + implementation "com.squareup.retrofit2:converter-gson:$retorfit_version" + + + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' + + implementation 'com.synnapps:carouselview:0.1.5' + + implementation 'de.hdodenhof:circleimageview:3.1.0' + + implementation("androidx.viewpager2:viewpager2:1.0.0") + + implementation 'com.google.code.gson:gson:2.9.0' + + +} +kapt { + correctErrorTypes = true + +} \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..77801cc --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,39 @@ +{ + "project_info": { + "project_number": "546168156556", + "project_id": "mvvmdemowithdi", + "storage_bucket": "mvvmdemowithdi.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:546168156556:android:753224458e6d62c31066a9", + "android_client_info": { + "package_name": "com.ketub4.mvvmdemowithdi" + } + }, + "oauth_client": [ + { + "client_id": "546168156556-svdf9jakr5235qagvfuc8dli8en8s6bn.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyB4pEVksO097Lvl4FtEusECeQFIwkOVeVM" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "546168156556-svdf9jakr5235qagvfuc8dli8en8s6bn.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/ketub4/mvvmdemowithdi/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/ketub4/mvvmdemowithdi/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..7c82420 --- /dev/null +++ b/app/src/androidTest/java/com/ketub4/mvvmdemowithdi/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.ketub4.mvvmdemowithdi + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.ketub4.mvvmdemowithdi", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..06f9234 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/AppointmentDetailsActivity.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/AppointmentDetailsActivity.kt new file mode 100644 index 0000000..9645eb0 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/AppointmentDetailsActivity.kt @@ -0,0 +1,161 @@ +package com.ketub4.mvvmdemowithdi.activities + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import android.view.WindowManager +import android.widget.Toast +import com.google.gson.Gson +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.databinding.ActivityAppointmentDetailsBinding +import com.ketub4.mvvmdemowithdi.model.Doctors +import java.util.regex.Matcher +import java.util.regex.Pattern + + +class AppointmentDetailsActivity : AppCompatActivity() { + private var _binding: ActivityAppointmentDetailsBinding? = null + private val binding: ActivityAppointmentDetailsBinding get() = _binding!! + private val VALID_EMAIL_ADDRESS_REGEX: Pattern = + Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE) + private val gson = Gson() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + _binding = ActivityAppointmentDetailsBinding.inflate(layoutInflater) + setContentView(binding.root) + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + binding.appBar.toolbarTitle.text = "Personal Details" + + _binding?.appBar?.back?.setOnClickListener { + finish() + } + _binding?.appBar?.rightIcon?.visibility = View.INVISIBLE + + val doctorObjString = intent.extras?.get("doctorObj").toString() + if (doctorObjString.isNotEmpty()){ + setupDoctorDetails(doctorObjString) + } + + binding.DoneBtn.setOnClickListener { + if (validateInputs()){ + val intent = Intent(this@AppointmentDetailsActivity, SuccessfulActivity::class.java) + startActivity(intent) + } + } + + + } + + private fun setupDoctorDetails(doctorData:String){ + val doctor = gson.fromJson(doctorData, Doctors::class.java) + _binding?.doctorDetails?.apply { + doctorName.text = doctor.name + categoryName.text = doctor.category + distance.text = "Distance: "+doctor.distance + address.text = doctor.address + categoryImage.setImageResource(this@AppointmentDetailsActivity.resources.getIdentifier( + getImageName(doctor.name), "drawable", "com.ketub4.mvvmdemowithdi")); + setRatingView(doctor.rating) + } + } + + fun validateInputs():Boolean{ + if (binding.name.text.isEmpty()){ + binding.name.error = "Enter your Name" + // Toast.makeText(this, "Enter Your Name", Toast.LENGTH_SHORT).show() + return false + } + + if (binding.mobile.text.isEmpty()){ + binding.mobile.error = "Enter Your Phone Number" + //Toast.makeText(this, "Enter Your Phone Number", Toast.LENGTH_SHORT).show() + return false + }else if (binding.mobile.text.length != 10){ + binding.mobile.error = "Enter Your 10 Digit Phone Number" + //Toast.makeText(this, "Enter Your 10 Digit Phone Number", Toast.LENGTH_SHORT).show() + return false + } + if (binding.email.text.isEmpty()){ + binding.email.error = "Enter Your Email Id" + //Toast.makeText(this, "Enter Your Email Id", Toast.LENGTH_SHORT).show() + return false + }else if (!validateEmail(binding.email.text.toString())){ + binding.email.error = "Enter Valid Email Id" + //Toast.makeText(this, "Enter Valid Email Id", Toast.LENGTH_SHORT).show() + return false + } + if (binding.comments.text.isEmpty()){ + binding.comments.error = "Enter details of the illness" + //Toast.makeText(this, "Enter details of the illness", Toast.LENGTH_SHORT).show() + return false + } + return true + } + + + + fun validateEmail(emailStr: String): Boolean { + val matcher: Matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailStr) + return matcher.find() + } + + private fun getImageName(doctorName:String):String{ + var imageName = "doc_m2" // demo purpose hard coded + if (doctorName.contains("Urmila") || doctorName.contains("Varsha") ||doctorName.contains("Vasanti")) + { + // For demo project this condition is applied. In actual get the profile pic from API. + imageName = "doc_f1" + } + + return imageName + } + + private fun setRatingView(rating: Int) { + if (rating==1){ + _binding?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start) + rate3.setImageResource(R.drawable.start) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==2){ + _binding?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==3){ + _binding?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==4){ + _binding?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start_filled) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==5){ + _binding?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start_filled) + rate5.setImageResource(R.drawable.start_filled) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/BookAppointmentActivity.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/BookAppointmentActivity.kt new file mode 100644 index 0000000..7b8c7b2 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/BookAppointmentActivity.kt @@ -0,0 +1,342 @@ +package com.ketub4.mvvmdemowithdi.activities + +import android.content.Intent +import android.os.Build +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import android.view.View +import android.widget.Toast +import androidx.activity.viewModels +import androidx.annotation.RequiresApi +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.GridLayoutManager +import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.widget.ViewPager2 +import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.google.gson.Gson +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.adapter.* +import com.ketub4.mvvmdemowithdi.databinding.ActivityBookAppointmentBinding +import com.ketub4.mvvmdemowithdi.fragments.SearchFragment +import com.ketub4.mvvmdemowithdi.model.Appointment +import com.ketub4.mvvmdemowithdi.model.Doctors +import com.ketub4.mvvmdemowithdi.utils.CalendarUtils +import com.ketub4.mvvmdemowithdi.utils.CalendarUtils.Companion.daysInWeekArray +import com.ketub4.mvvmdemowithdi.viewModel.CustomViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.time.LocalDate + +@AndroidEntryPoint +class BookAppointmentActivity : AppCompatActivity(), ITimeSlotLitener, IViewPagerListener, + ICalendarAdapter { + private var _binding: ActivityBookAppointmentBinding? = null + private val binding: ActivityBookAppointmentBinding get() = _binding!! + private val customViewModel: CustomViewModel by viewModels() + private var category_name: String = "" + lateinit var appointmentAdapter: AppointmentAdapter + lateinit var timeslotList: ArrayList + lateinit var viewPager2Adapter: ViewPager2Adapter + lateinit var calendarAdapter: CalendarAdapter + lateinit var sortedfList: ArrayList + private val gson = Gson() + private var bookedTimeSlot: String = "" + @RequiresApi(Build.VERSION_CODES.O) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + _binding = ActivityBookAppointmentBinding.inflate(layoutInflater) + setContentView(binding.root) + title = "" + + setSupportActionBar(binding.appBar.toolbar) + binding.appBar.toolbarTitle.text = "Book Appointment" + + _binding?.appBar?.back?.setOnClickListener { + finish() + } + _binding?.appBar?.rightIcon?.visibility = View.INVISIBLE + val doctorObjString = intent.extras?.get("doctorObj").toString() + if (doctorObjString.isNotEmpty()){ + setupDoctorDetails(doctorObjString) + } + + loadTimeSlots("22/02/2022",1, true)//for demo purpose + + binding.viewpager.registerOnPageChangeCallback(object : OnPageChangeCallback() { + // This method is triggered when there is any scrolling activity for the current page + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + super.onPageScrolled(position, positionOffset, positionOffsetPixels) + //Log.i("onPageScrolled","Scrolling="+position) + } + + // triggered when you select a new page + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + Log.i("onPageSelected","Scrolling="+position) + sortedListData(position) + + } + + // triggered when there is + // scroll state will be changed + override fun onPageScrollStateChanged(state: Int) { + super.onPageScrollStateChanged(state) + //Log.i("onPageScrollState","Scrolling="+state) + } + }) + + binding.nextBtn.setOnClickListener { + if (bookedTimeSlot.isEmpty()){ + Toast.makeText(this@BookAppointmentActivity, "Please select the Time.", Toast.LENGTH_SHORT).show() + }else{ + val intent = Intent(this@BookAppointmentActivity, AppointmentDetailsActivity::class.java) + intent.putExtra("doctorObj",doctorObjString) + startActivity(intent) + } + + } + + } + + private fun setupDoctorDetails(doctorData:String){ + val doctor = gson.fromJson(doctorData, Doctors::class.java) + _binding?.calendarView?.doctorDetails?.apply { + doctorName.text = doctor.name + categoryName.text = doctor.category + distance.text = "Distance: "+doctor.distance + address.text = doctor.address + categoryImage.setImageResource(this@BookAppointmentActivity.resources.getIdentifier( + getImageName(doctor.name), "drawable", "com.ketub4.mvvmdemowithdi")); + setRatingView(doctor.rating) + } + } + @RequiresApi(Build.VERSION_CODES.O) + private fun loadTimeSlots(date: String, doctorId: Int, isFirstTime: Boolean){ + showHideProgressBar() + customViewModel.getTimeSlots(date, doctorId) //For demo this is hard coded. + + GlobalScope.launch(Dispatchers.Main) { + if (isFirstTime){ + setupWeekCalendar() + }else{ + sortedfList.clear() + appointmentAdapter.updateTimeSlotList(sortedfList) + } + delay(2000) + customViewModel.timeSlotList.observe(this@BookAppointmentActivity, Observer { list -> + Log.i("timeSlotList", "=$list") + timeslotList = list + if (list.size>0) + showHideProgressBar() + + }) + + setupPageViewer() + + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun setupWeekCalendar() { + Log.i("selectedDate", "selectedDate=" + LocalDate.now()) + binding.calendarView.monthYearTV.text = + CalendarUtils.monthYearFromDate(CalendarUtils.selectedDate) + val days: ArrayList = CalendarUtils.daysInWeekArray(CalendarUtils.selectedDate) + + + calendarAdapter = CalendarAdapter(days, this) + + binding.calendarView.calendarRecyclerView.apply { + layoutManager = GridLayoutManager(this@BookAppointmentActivity, 7) + hasFixedSize() + adapter = calendarAdapter + } + + binding.calendarView.previousWeek.setOnClickListener { + val oldDate = CalendarUtils.selectedDate.minusWeeks(1) + if (oldDate < LocalDate.now()) { + Toast.makeText( + this@BookAppointmentActivity, + "You can not select Previous Week.", + Toast.LENGTH_SHORT + ) + .show() + } else { + CalendarUtils.selectedDate = oldDate + setupWeekCalendar() + } + + + } + binding.calendarView.nextWeek.setOnClickListener { + + CalendarUtils.selectedDate = CalendarUtils.selectedDate.plusWeeks(1) + setupWeekCalendar() + } + binding.calendarView.calenderIcon.setOnClickListener { + val isVisibile = binding.calendarView.calendarMainView.visibility + Log.i("isVisibile", "isVisibile=" + isVisibile) + if (isVisibile == View.VISIBLE) { + binding.calendarView.calendarMainView.visibility = View.GONE + } else { + binding.calendarView.calendarMainView.visibility = View.VISIBLE + } + } + } + + private fun setupPageViewer() { + sortedfList = timeslotList.filter { + s->s.timeSlot == "m" + } as ArrayList + Log.i("morningList="+sortedfList.size,"morningList="+sortedfList.toString()) + appointmentAdapter = AppointmentAdapter(sortedfList,this, this) + viewPager2Adapter = + ViewPager2Adapter(this@BookAppointmentActivity, appointmentAdapter,this) + binding.viewpager.apply { + adapter = viewPager2Adapter + } + } + + override fun onTimeSlotClicked(appointId: Int, isBooked: Boolean, time: String) { + if (isBooked) { + Toast.makeText( + this@BookAppointmentActivity, + "TimeSlot Already Booked.", + Toast.LENGTH_SHORT + ) + .show() + bookedTimeSlot = "" + } else { + bookedTimeSlot = time + } + } + + override fun nextPage() { + + binding.viewpager.currentItem = binding.viewpager.currentItem + 1 + val currentItem = binding.viewpager.currentItem + Log.i("currentItem123","currentItem="+currentItem) + sortedListData(currentItem) + } + + override fun previousPage() { + binding.viewpager.currentItem = binding.viewpager.currentItem - 1 + val currentItem = binding.viewpager.currentItem + Log.i("currentItem","currentItem="+currentItem) + sortedListData(currentItem) + } + + private fun sortedListData(currentPos:Int){ + sortedfList.clear() + when(currentPos){ + 0->{ + sortedfList = timeslotList.filter { s->s.timeSlot == "m" } as ArrayList + true + } + 1->{ + sortedfList = timeslotList.filter { s->s.timeSlot == "a" } as ArrayList + true + } + 2->{ + sortedfList = timeslotList.filter { s->s.timeSlot == "e" } as ArrayList + true + } + + } + Log.i("morningList="+sortedfList.size,"morningList="+sortedfList.toString()) + appointmentAdapter.updateTimeSlotList(sortedfList) + } + + + @RequiresApi(Build.VERSION_CODES.O) + override fun onCalendarItemClicked(position: Int, localDate: LocalDate) { + if (localDate < LocalDate.now()) { + Toast.makeText( + this@BookAppointmentActivity, + "You can not Select Older dates.", + Toast.LENGTH_SHORT + ).show() + } else { + CalendarUtils.selectedDate = localDate + setupWeekCalendar() + + loadTimeSlots("22/02/2022",1, false)//for demo same date and doctor id + } + + } + + private fun showHideProgressBar() { + binding.progressBar + if (binding.progressBar.visibility== View.VISIBLE){ + binding.progressBar.visibility = View.GONE + }else{ + binding.progressBar.visibility = View.VISIBLE + } + + } + + private fun getImageName(doctorName:String):String{ + var imageName = "doc_m2" // demo purpose hard coded + if (doctorName.contains("Urmila") || doctorName.contains("Varsha") ||doctorName.contains("Vasanti")) + { + // For demo project this condition is applied. In actual get the profile pic from API. + imageName = "doc_f1" + } + + return imageName + } + + private fun setRatingView(rating: Int) { + if (rating==1){ + _binding?.calendarView?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start) + rate3.setImageResource(R.drawable.start) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==2){ + _binding?.calendarView?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==3){ + _binding?.calendarView?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==4){ + _binding?.calendarView?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start_filled) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==5){ + _binding?.calendarView?.doctorDetails?.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start_filled) + rate5.setImageResource(R.drawable.start_filled) + } + } + } + +} + diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/DoctorListActivity.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/DoctorListActivity.kt new file mode 100644 index 0000000..0a5638e --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/DoctorListActivity.kt @@ -0,0 +1,94 @@ +package com.ketub4.mvvmdemowithdi.activities + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import android.view.View +import androidx.activity.viewModels +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.gson.Gson +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.adapter.DoctorListAdapter +import com.ketub4.mvvmdemowithdi.adapter.IDoctorListAdapter +import com.ketub4.mvvmdemowithdi.databinding.ActivityDoctorListBinding +import com.ketub4.mvvmdemowithdi.databinding.ActivityMainBinding +import com.ketub4.mvvmdemowithdi.model.Doctors +import com.ketub4.mvvmdemowithdi.viewModel.CustomViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +@AndroidEntryPoint +class DoctorListActivity : AppCompatActivity(), IDoctorListAdapter { + private var _binding: ActivityDoctorListBinding?=null + private val binding: ActivityDoctorListBinding get() = _binding!! + private val customViewModel: CustomViewModel by viewModels() + private var category_id:Int = 0 + private var category_name: String="" + lateinit var doctorListAdapter:DoctorListAdapter + lateinit var doctorList: ArrayList + private val gson = Gson() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + _binding = ActivityDoctorListBinding.inflate(layoutInflater) + setContentView(binding.root) + title = "" + + setSupportActionBar(binding.appBarMain.toolbar) + supportActionBar?.setDisplayShowHomeEnabled(true) + category_id = intent.extras!!.getInt("categoryId") + category_name = intent.extras!!.getString("categoryName")!! + binding.appBarMain.toolbarTitle.text = category_name+" Doctors List" + showHideProgressBar() + customViewModel.getDoctorsList(category_id) + + GlobalScope.launch(Dispatchers.Main) { + delay(1500) + customViewModel.doctorsList.observe(this@DoctorListActivity, Observer { list-> + Log.i("DoctorList", "=$list") + doctorList = list + if (list.size>0) + showHideProgressBar() + + }) + setupRV() + } + + binding.appBarMain.back.setOnClickListener { + this.finish() + } + + + + } + + private fun setupRV() { + doctorListAdapter = DoctorListAdapter(doctorList, this, this@DoctorListActivity) + binding.recyclerView.apply { + layoutManager = LinearLayoutManager(this@DoctorListActivity) + hasFixedSize() + adapter = doctorListAdapter + } + + } + + override fun onBookBtnClick(doctor: Doctors) { + val intent = Intent(this, BookAppointmentActivity::class.java) + val objString = gson.toJson(doctor) + intent.putExtra("doctorObj",objString) + startActivity(intent) + } + + private fun showHideProgressBar() { + if (_binding!!.proressBar.visibility== View.VISIBLE){ + _binding!!.proressBar.visibility = View.GONE + }else{ + _binding!!.proressBar.visibility = View.VISIBLE + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/MainActivity.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/MainActivity.kt new file mode 100644 index 0000000..28dd6f8 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/MainActivity.kt @@ -0,0 +1,166 @@ +package com.ketub4.mvvmdemowithdi.activities + +import android.graphics.Color +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import android.view.animation.TranslateAnimation +import androidx.activity.viewModels +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction +import androidx.navigation.NavController +import androidx.navigation.findNavController +import androidx.navigation.ui.setupWithNavController +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.bottomnavigation.BottomNavigationView +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.adapter.DrawerMenuAdapter +import com.ketub4.mvvmdemowithdi.adapter.IDrawerMenuAdapter +import com.ketub4.mvvmdemowithdi.databinding.ActivityMainBinding +import com.ketub4.mvvmdemowithdi.fragments.SearchFragment + +import com.ketub4.mvvmdemowithdi.network.FirebaseService +import com.ketub4.mvvmdemowithdi.viewModel.CustomViewModel +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : AppCompatActivity(), IDrawerMenuAdapter { + private var _binding: ActivityMainBinding?=null + val binding: ActivityMainBinding get() = _binding!! + private val customViewModel: CustomViewModel by viewModels() + lateinit var listener: FirebaseService + private var drawerOpened: Boolean = false + lateinit var drawerMenuAdapter: DrawerMenuAdapter + lateinit var navController: NavController + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + _binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + setupNavigation() + title="" + actionBar?.elevation= 0f + setSupportActionBar(binding.mainAppBar.toolbar) + binding.mainAppBar.appbarLayout.outlineProvider = null + binding.mainAppBar.toolbarTitle.text = "Mumbai" + + binding.mainAppBar.home.setOnClickListener { + toggleDrawerNavigation() + } + binding.mainAppBar.homeSearch.setOnClickListener { + navController.navigate(R.id.searchFragment) + } + + binding.drawerInnerLayout.backBtn.setOnClickListener { + toggleDrawerNavigation() + } + drawerMenuAdapter = DrawerMenuAdapter(this) + binding.menuRV.apply { + layoutManager = LinearLayoutManager(this@MainActivity) + hasFixedSize() + adapter = drawerMenuAdapter + } + +// binding.menuItem1.setOnClickListener { +// binding.menuItem1.setBackgroundResource(R.drawable.background_shape_square_blue) +// binding.menuText1.setTextColor(Color.WHITE) +// binding.menuImage1.setColorFilter(Color.argb(255, 255, 255, 255)); +// } +// binding.menuItem2.setOnClickListener { +// binding.menuItem2.setBackgroundResource(R.drawable.background_shape_square_blue) +// binding.menuText2.setTextColor(Color.WHITE) +// binding.menuImage2.setColorFilter(Color.argb(255, 255, 255, 255)); +// } + + // movieViewModel.getMovieData(); + //movieViewModel.getCategoryList() +// customViewModel.movieList.observe(this, Observer { list-> +// Log.i("data=","data"+list.size) +// }) + + //movieViewModel.insertRecords() + //movieViewModel.insertDoctorData() + +// GlobalScope.launch(Dispatchers.Main) { +// delay(3000) +// movieViewModel.categoryList.observe(this@MainActivity, Observer { list-> +// Log.i("category=","category"+list.toString()) +// }) +// } + + + + + + } + + + + private fun setupNavigation() { + val navView: BottomNavigationView = _binding!!.bottomNavigation + + navController = findNavController(R.id.fragmentContainerView) + + navView.setupWithNavController(navController) + } + + private fun toggleDrawerNavigation() { + if (!drawerOpened){ + binding.drawerLayout.visibility = View.VISIBLE + val animate = TranslateAnimation( + -binding.drawerLayout.width.toFloat(), + 0F, + 0f, + 0F + ) + animate.duration = 500 + animate.fillAfter = true + binding.drawerLayout.startAnimation(animate) + binding.menuRV.visibility = View.VISIBLE + }else{ + binding.drawerLayout.visibility = View.GONE + val animate = TranslateAnimation( + 0F, + -binding.drawerLayout.width.toFloat(), + 0F, + 0F + ) + animate.duration = 500 + animate.fillAfter = true + binding.drawerLayout.startAnimation(animate) + binding.menuRV.visibility = View.GONE + + } + //binding.drawerLayout.setOnClickListener(null) + drawerOpened = !drawerOpened + } + + override fun onMenuItemClicked(id:Int) { + toggleDrawerNavigation() + when(id){ + 0->{ + navController.navigate(R.id.homeFragment) + true + } + 1->{ + navController.navigate(R.id.searchFragment) + true + } + 2->{ + navController.navigate(R.id.notificationFragment2) + true + } + 3->{ + navController.navigate(R.id.profileFragment) + true + } + else ->{ + navController.navigate(R.id.homeFragment) + true + } + } + + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/SuccessfulActivity.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/SuccessfulActivity.kt new file mode 100644 index 0000000..f455df0 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/SuccessfulActivity.kt @@ -0,0 +1,32 @@ +package com.ketub4.mvvmdemowithdi.activities + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import com.ketub4.mvvmdemowithdi.databinding.ActivitySuccessfulBinding + +class SuccessfulActivity : AppCompatActivity() { + private var _binding: ActivitySuccessfulBinding? = null + private val binding: ActivitySuccessfulBinding get() = _binding!! + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + _binding = ActivitySuccessfulBinding.inflate(layoutInflater) + setContentView(binding.root) + + _binding?.appBar?.toolbarTitle?.text = "Confirmation" + _binding?.appBar?.rightIcon?.visibility = View.INVISIBLE + _binding?.homeBtn?.setOnClickListener { + launchMainActivity() + } + _binding?.appBar?.back?.setOnClickListener { + launchMainActivity() + } + } + + private fun launchMainActivity(){ + val intent = Intent(this@SuccessfulActivity, MainActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + startActivity(intent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/WelcomeActivity.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/WelcomeActivity.kt new file mode 100644 index 0000000..cad40f6 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/activities/WelcomeActivity.kt @@ -0,0 +1,23 @@ +package com.ketub4.mvvmdemowithdi.activities + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import com.ketub4.mvvmdemowithdi.databinding.ActivityWelcomeBinding +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class WelcomeActivity : AppCompatActivity() { + private var _binding: ActivityWelcomeBinding?=null + private val binding: ActivityWelcomeBinding get() = _binding!! + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + _binding = ActivityWelcomeBinding.inflate(layoutInflater) + setContentView(binding.root) + + binding.proceedBtn.setOnClickListener { + val intent = Intent(this@WelcomeActivity, MainActivity::class.java) + startActivity(intent) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/AppointmentAdapter.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/AppointmentAdapter.kt new file mode 100644 index 0000000..2af256a --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/AppointmentAdapter.kt @@ -0,0 +1,83 @@ +package com.ketub4.mvvmdemowithdi.adapter + +import android.content.Context +import android.graphics.Color +import android.util.Log +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.databinding.TimeItemBinding +import com.ketub4.mvvmdemowithdi.model.Appointment + +class AppointmentAdapter(private var appointmentList: ArrayList, + private val listener:ITimeSlotLitener, + private val context:Context):RecyclerView.Adapter() { + + class AppointmentViewHolder(val binding: TimeItemBinding): RecyclerView.ViewHolder(binding.root) + + private var selectedPosition: Int? = -1 + private var selectedTime: String = "" + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppointmentViewHolder { + return (AppointmentViewHolder( + TimeItemBinding.inflate(LayoutInflater.from(parent.context), + parent, false) + )) + } + + override fun onBindViewHolder(holder: AppointmentViewHolder, position: Int) { + val appointment = appointmentList[position] + holder.binding.apply { + appointTime.text = appointment.time + + appointTime.setOnClickListener { + if (!appointment.booked){ + if (selectedPosition == holder.adapterPosition){ + selectedPosition = RecyclerView.NO_POSITION + notifyDataSetChanged() + selectedTime = "" + listener.onTimeSlotClicked(appointment.id, appointment.booked, selectedTime) + return@setOnClickListener + } + selectedTime = appointment.time + selectedPosition = holder.adapterPosition + notifyDataSetChanged() + listener.onTimeSlotClicked(appointment.id, appointment.booked, selectedTime) + } + Log.i("selectedTime=","selectedTime="+selectedTime) + + } + + if (selectedPosition==position){ + appointTime.setBackgroundResource(R.drawable.background_shape_green) + appointTime.setTextColor(Color.WHITE) + + }else{ + appointTime.setBackgroundResource(R.drawable.background_shape_white) + appointTime.setTextColor(context.resources.getColor(R.color.basicGreen)) + + } + Log.i("appointment.isBooked","selectedTime outside="+selectedTime) + if (appointment.booked){ + appointTime.setBackgroundResource(R.drawable.background_shape_gray) + appointTime.setTextColor(Color.BLACK) + selectedTime = "" + } + + } + } + + override fun getItemCount(): Int = appointmentList.size + + fun updateTimeSlotList(newList: ArrayList){ + appointmentList.clear() + appointmentList = newList + notifyDataSetChanged() + } + + +} + +interface ITimeSlotLitener{ + fun onTimeSlotClicked(appointId:Int, isBooked:Boolean, time: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/CalendarAdapter.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/CalendarAdapter.kt new file mode 100644 index 0000000..301f474 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/CalendarAdapter.kt @@ -0,0 +1,54 @@ +package com.ketub4.mvvmdemowithdi.adapter + +import android.graphics.Color +import android.os.Build +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.RequiresApi +import androidx.recyclerview.widget.RecyclerView +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.databinding.CalendarCellBinding +import com.ketub4.mvvmdemowithdi.utils.CalendarUtils +import java.time.LocalDate +import java.util.ArrayList + +class CalendarAdapter(private val days: ArrayList, + private val listener:ICalendarAdapter):RecyclerView.Adapter() { + + class CalendarViewHolder(val binding: CalendarCellBinding): RecyclerView.ViewHolder(binding.root) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CalendarViewHolder { + return (CalendarViewHolder(CalendarCellBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ))) + + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onBindViewHolder(holder: CalendarViewHolder, position: Int) { + val localDate = days[position] + if (localDate== null){ + holder.binding.cellDayText.text = "" + }else{ + holder.binding.cellDayText.text = localDate.dayOfMonth.toString() + if (localDate == CalendarUtils.selectedDate){ + holder.binding.parentView.setBackgroundResource(R.drawable.background_shape_blue) + holder.binding.cellDayText.setTextColor(Color.WHITE) + } + holder.binding.parentView.setOnClickListener { + listener.onCalendarItemClicked(holder.adapterPosition, localDate) + } + } + + } + + override fun getItemCount() = days.size + + +} + +interface ICalendarAdapter{ + fun onCalendarItemClicked(position: Int, localDate: LocalDate) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/CategoryAdapter.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/CategoryAdapter.kt new file mode 100644 index 0000000..a1773a5 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/CategoryAdapter.kt @@ -0,0 +1,52 @@ +package com.ketub4.mvvmdemowithdi + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.ketub4.mvvmdemowithdi.databinding.CateoryItemBinding +import com.ketub4.mvvmdemowithdi.model.Category +import java.util.* +import kotlin.collections.ArrayList + +class CategoryAdapter(private val listener: ICategoryListener, + private val categoryList: ArrayList, + private val context: Context):RecyclerView.Adapter() { + + class CategoryViewHolder(val binding: CateoryItemBinding):RecyclerView.ViewHolder(binding.root) + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder { + return CategoryViewHolder( + CateoryItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) { + + val category = categoryList[position] + holder.binding.apply { + categoryTitle.text = category.name + subCategoryTitle.text = category.description + val imageName = "cat_"+category.id + categoryImage.setImageResource(context.resources.getIdentifier( + imageName, "drawable", "com.ketub4.mvvmdemowithdi")); + categoryLayout.setOnClickListener { + listener.onCategoryClick(category.id, category.name) + } + + + } + } + + override fun getItemCount() = categoryList.size +} + +interface ICategoryListener{ + fun onCategoryClick(category_id:Int, category_name: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/DoctotListAdapter.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/DoctotListAdapter.kt new file mode 100644 index 0000000..d323579 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/DoctotListAdapter.kt @@ -0,0 +1,109 @@ +package com.ketub4.mvvmdemowithdi.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.databinding.DoctorListItemBinding +import com.ketub4.mvvmdemowithdi.model.Doctors + +class DoctorListAdapter(private val doctorList: ArrayList, + private val listener: IDoctorListAdapter, + private val context: Context): + RecyclerView.Adapter() { + + class DoctorListViewHolder(val binding: DoctorListItemBinding): RecyclerView.ViewHolder(binding.root) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DoctorListViewHolder { + return DoctorListViewHolder( + DoctorListItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: DoctorListViewHolder, position: Int) { + val doctor = doctorList[position] + holder.binding.apply { + categoryName.text = doctor.category + doctorName.text = doctor.name + distance.text = "Distance: "+doctor.distance + address.text = doctor.address + setRatingView(doctor.rating, holder) + + var imageName = "doc_m2" + if (doctor.name.contains("Urmila") || doctor.name.contains("Varsha") ||doctor.name.contains("Vasanti")) + { + // For demo project this condition is applied. In actual get the profile pic from API. + imageName = "doc_f1" + } + + categoryImage.setImageResource(context.resources.getIdentifier( + imageName, "drawable", "com.ketub4.mvvmdemowithdi")); + + bookBtn.setOnClickListener { + listener.onBookBtnClick(doctor) + } + + } + } + + + + override fun getItemCount()= doctorList.size + + private fun setRatingView(rating: Int, holder: DoctorListViewHolder) { + if (rating==1){ + holder.binding.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start) + rate3.setImageResource(R.drawable.start) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==2){ + holder.binding.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==3){ + holder.binding.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==4){ + holder.binding.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start_filled) + rate5.setImageResource(R.drawable.start) + } + } + if (rating==5){ + holder.binding.apply { + rate1.setImageResource(R.drawable.start_filled) + rate2.setImageResource(R.drawable.start_filled) + rate3.setImageResource(R.drawable.start_filled) + rate4.setImageResource(R.drawable.start_filled) + rate5.setImageResource(R.drawable.start_filled) + } + } + } +} + +interface IDoctorListAdapter{ + fun onBookBtnClick(doctor: Doctors) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/DrawerMenuAdapter.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/DrawerMenuAdapter.kt new file mode 100644 index 0000000..12f2f11 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/DrawerMenuAdapter.kt @@ -0,0 +1,90 @@ +package com.ketub4.mvvmdemowithdi.adapter + +import android.graphics.Color +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.ketub4.mvvmdemowithdi.databinding.DrawerMenuItemBinding +import com.ketub4.mvvmdemowithdi.R + +class DrawerMenuAdapter(private val listener:IDrawerMenuAdapter):RecyclerView.Adapter() { + + class MenuViewHolder(val binding: DrawerMenuItemBinding): RecyclerView.ViewHolder(binding.root) + + private val menuList:ArrayList = ArrayList(4) + private var selectedPosition: Int? = -1 + init { + menuList.add("Home") + menuList.add("Search") + menuList.add("Notifications") + menuList.add("Profile") + + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MenuViewHolder { + return (MenuViewHolder(DrawerMenuItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ))) + } + + override fun onBindViewHolder(holder: MenuViewHolder, position: Int) { + val menu = menuList[position] + holder.binding.apply { + menuText.text = menu + when(menu){ + "Home"->{ + menuImage.setImageResource(R.drawable.home) + true + } + "Search"->{ + menuImage.setImageResource(R.drawable.search) + true + } + "Notifications"->{ + menuImage.setImageResource(R.drawable.notification) + true + } + "Profile"->{ + menuImage.setImageResource(R.drawable.profile) + true + } + else->{ + menuImage.setImageResource(R.drawable.home) + true + } + } + + holder.binding.menuItem.setOnClickListener { + if (selectedPosition == holder.adapterPosition){ + selectedPosition = RecyclerView.NO_POSITION + notifyDataSetChanged() + return@setOnClickListener + } + selectedPosition = holder.adapterPosition + notifyDataSetChanged() + + listener.onMenuItemClicked(position) + } + + if (selectedPosition == position){ + menuItem.setBackgroundResource(R.drawable.background_shape_square_blue) + menuText.setTextColor(Color.WHITE) + menuImage.setColorFilter(Color.argb(255, 255, 255, 255)); + }else{ + menuItem.setBackgroundResource(R.drawable.background_shape_white) + menuText.setTextColor(Color.BLACK) + menuImage.setColorFilter(Color.argb(0, 0, 0, 0)); + } + + } + } + + override fun getItemCount()= menuList.size + + +} + +interface IDrawerMenuAdapter{ + fun onMenuItemClicked(id:Int) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/NotificationAdapter.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/NotificationAdapter.kt new file mode 100644 index 0000000..db623a2 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/NotificationAdapter.kt @@ -0,0 +1,99 @@ +package com.ketub4.mvvmdemowithdi.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.databinding.NotificationItemBinding +import com.ketub4.mvvmdemowithdi.model.Notification + +class NotificationAdapter( + private val notificatioList: ArrayList, + private val context: Context +): RecyclerView.Adapter() { + + class NotificationViewHolder(val binding: NotificationItemBinding): RecyclerView.ViewHolder(binding.root) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NotificationViewHolder { + return NotificationViewHolder( + NotificationItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + + ) + } + + override fun onBindViewHolder(holder: NotificationViewHolder, position: Int) { + val notification = notificatioList[position] + holder.binding.apply { + notificationTitle.text = notification.title + notificationText.text = notification.message + notificationDate.text = notification.date + + val imageName = "cat_"+notification.categoryId + categoryImage.setImageResource(context.resources.getIdentifier( + imageName, "drawable", "com.ketub4.mvvmdemowithdi")); + + when(notification.categoryId){ + 1->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicGreen)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicGreen)) + true + } + 2->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicOrange)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicOrange)) + true + } + 3->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicBlue)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicBlue)) + true + } + 4->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicGreen)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicGreen)) + true + } + 5->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicYellow)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicYellow)) + true + } + 6->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicBlue)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicBlue)) + true + } + 7->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicGreen)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicGreen)) + true + } + 8->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicBlue)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicBlue)) + true + } + 10->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicOrange)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicOrange)) + true + } + else ->{ + leftBar.setBackgroundColor(context.resources.getColor(R.color.basicPink)) + rightBar.setBackgroundColor(context.resources.getColor(R.color.basicPink)) + true + } + } + + } + } + + override fun getItemCount()= notificatioList.size + + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/ViewPager2Adapter.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/ViewPager2Adapter.kt new file mode 100644 index 0000000..b46c777 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/adapter/ViewPager2Adapter.kt @@ -0,0 +1,71 @@ +package com.ketub4.mvvmdemowithdi.adapter + +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.ketub4.mvvmdemowithdi.databinding.ViewpagerItemBinding + +import android.content.Context +import android.util.Log +import android.view.LayoutInflater +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.model.Appointment + + + + + + +class ViewPager2Adapter(private val context: Context, + private val appointmentAdapter: AppointmentAdapter, + private val listener: IViewPagerListener):RecyclerView.Adapter() { + + class PageViewHolder(val binding: ViewpagerItemBinding): RecyclerView.ViewHolder(binding.root) + + private val timings = arrayOf( + "Morning", "Afternoon", "Evening" + ) + private val timeImages = intArrayOf( + R.drawable.morning, + R.drawable.afternoon, + R.drawable.night, + + ) + + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageViewHolder { + return (PageViewHolder(ViewpagerItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ))) + } + + override fun onBindViewHolder(holder: PageViewHolder, position: Int) { + + holder.binding.apply { + recyclerView.layoutManager = GridLayoutManager(context,4) + recyclerView.hasFixedSize() + recyclerView.adapter = appointmentAdapter + Log.i("position","position="+position) + pageTitle.text = timings[position] + pageTitleImage.setImageResource(timeImages[position]) + + previous.setOnClickListener { + listener.previousPage() + } + next.setOnClickListener { + listener.nextPage() + } + + } + } + + override fun getItemCount()=timings.size +} + +interface IViewPagerListener{ + fun nextPage() + fun previousPage() +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/container/BaseApplication.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/container/BaseApplication.kt new file mode 100644 index 0000000..406898d --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/container/BaseApplication.kt @@ -0,0 +1,8 @@ +package com.ketub4.mvvmdemowithdi.container + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class BaseApplication:Application() { +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/di/AppModule.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/di/AppModule.kt new file mode 100644 index 0000000..1029477 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/di/AppModule.kt @@ -0,0 +1,44 @@ +package com.ketub4.mvvmdemowithdi.di + +import android.content.Context +import com.google.firebase.firestore.FirebaseFirestore +import com.ketub4.mvvmdemowithdi.network.APIService +import com.ketub4.mvvmdemowithdi.network.FirebaseService + +import com.ketub4.mvvmdemowithdi.utils.Constant +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class AppModule { + + @Provides + @Singleton + fun provideRetrofitInstance(): APIService{ + return Retrofit.Builder() + .baseUrl(Constant.BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(APIService::class.java) + } + + @Provides + @Singleton + fun provideFireStoreInstance():FirebaseFirestore { + return FirebaseFirestore.getInstance() + } + + @Provides + @Singleton + fun getContext(@ApplicationContext context: Context):Context{ + return context + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/HomeFragment.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/HomeFragment.kt new file mode 100644 index 0000000..d7afdaa --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/HomeFragment.kt @@ -0,0 +1,126 @@ +package com.ketub4.mvvmdemowithdi.fragments + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager + +import com.ketub4.mvvmdemowithdi.CategoryAdapter +import com.ketub4.mvvmdemowithdi.ICategoryListener +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.activities.DoctorListActivity +import com.ketub4.mvvmdemowithdi.databinding.FragmentHomeBinding + +import com.ketub4.mvvmdemowithdi.model.Category +import com.ketub4.mvvmdemowithdi.viewModel.CustomViewModel +import com.synnapps.carouselview.ImageListener +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class HomeFragment : Fragment(),ICategoryListener { + private var _binding: FragmentHomeBinding?=null + private val binding: FragmentHomeBinding get() = _binding!! + private val customViewModel: CustomViewModel by activityViewModels() + lateinit var categoryAdapter: CategoryAdapter + private lateinit var categoryList: ArrayList + + var sampleImages = intArrayOf( + R.drawable.banner_image1, + R.drawable.banner_image2, + R.drawable.banner_image1, + R.drawable.banner_image2, + R.drawable.banner_image1, + R.drawable.banner_image2, + ) + + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + _binding = FragmentHomeBinding.inflate(layoutInflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + customViewModel.getCategoryList() + //customViewModel.insertDoctorData() + showHideProgressBar() + + //setupRV() + +// customViewModel._categoryList.observe(requireActivity(), Observer { list-> +// Log.i("category=", "category$list") +// categoryList = list +// if (list.size>0) { +// showHideProgressBar() +// setupRV() +// } +// }) + + + GlobalScope.launch(Dispatchers.Main) { + delay(1500) + customViewModel.categoryList.observe(viewLifecycleOwner, Observer { list-> + Log.i("category=", "category$list") + categoryList = list + if (list.size>0) { + showHideProgressBar() + setupRV() + } + }) + + + } + + val imageListener = + ImageListener { position, imageView -> imageView.setImageResource(sampleImages[position]) } + _binding!!.carouselView.apply { + setImageListener(imageListener) + pageCount = sampleImages.size + + } + } + + private fun setupRV() { + categoryAdapter = CategoryAdapter(this,categoryList, requireContext()) + binding.categoryRV.apply { + layoutManager = LinearLayoutManager(requireContext()) + hasFixedSize() + adapter = categoryAdapter + } + + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onCategoryClick(category_id:Int, category_name:String) { + val intent = Intent(requireContext(), DoctorListActivity::class.java) + intent.putExtra("categoryId", category_id) + intent.putExtra("categoryName", category_name) + startActivity(intent) + } + + private fun showHideProgressBar() { + if (_binding!!.proressBar.visibility== View.VISIBLE){ + _binding!!.proressBar.visibility = View.GONE + }else{ + _binding!!.proressBar.visibility = View.VISIBLE + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/NotificationFragment.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/NotificationFragment.kt new file mode 100644 index 0000000..bf45741 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/NotificationFragment.kt @@ -0,0 +1,78 @@ +package com.ketub4.mvvmdemowithdi.fragments + +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.adapter.DoctorListAdapter +import com.ketub4.mvvmdemowithdi.adapter.NotificationAdapter +import com.ketub4.mvvmdemowithdi.databinding.FragmentNotificationBinding +import com.ketub4.mvvmdemowithdi.model.Notification +import com.ketub4.mvvmdemowithdi.viewModel.CustomViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + + +class NotificationFragment : Fragment() { + private var _binding: FragmentNotificationBinding?=null + private val binding: FragmentNotificationBinding get() = _binding!! + private val customViewModel: CustomViewModel by activityViewModels() + lateinit var notificationAdapter: NotificationAdapter + lateinit var notificationList: ArrayList + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + _binding = FragmentNotificationBinding.inflate(layoutInflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + showHideProgressBar() + + customViewModel.getNotifications() + GlobalScope.launch(Dispatchers.Main) { + delay(1500) + customViewModel.notificationsList.observe(requireActivity(), Observer { list -> + Log.i("doctors=", "doctors=${list.size}") + notificationList = list + if (list.size>0) + showHideProgressBar() + }) + setupRV() + } + + } + + private fun setupRV() { + notificationAdapter = NotificationAdapter(notificationList, requireActivity()) + binding.recyclerView.apply { + layoutManager = LinearLayoutManager(requireActivity()) + hasFixedSize() + adapter = notificationAdapter + } + + } + + private fun showHideProgressBar() { + if (_binding!!.progressBar.visibility== View.VISIBLE){ + _binding!!.progressBar.visibility = View.GONE + }else{ + _binding!!.progressBar.visibility = View.VISIBLE + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/ProfileFragment.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/ProfileFragment.kt new file mode 100644 index 0000000..b44ad4e --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/ProfileFragment.kt @@ -0,0 +1,24 @@ +package com.ketub4.mvvmdemowithdi.fragments + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.databinding.FragmentHomeBinding +import com.ketub4.mvvmdemowithdi.databinding.FragmentProfileBinding + +class ProfileFragment : Fragment() { + private var _binding: FragmentProfileBinding?=null + private val binding: FragmentProfileBinding get() = _binding!! + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + _binding = FragmentProfileBinding.inflate(layoutInflater, container, false) + return binding.root + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/SearchFragment.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/SearchFragment.kt new file mode 100644 index 0000000..f2031b6 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/fragments/SearchFragment.kt @@ -0,0 +1,87 @@ +package com.ketub4.mvvmdemowithdi.fragments + +import android.content.Intent +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.gson.Gson +import com.ketub4.mvvmdemowithdi.R +import com.ketub4.mvvmdemowithdi.activities.BookAppointmentActivity +import com.ketub4.mvvmdemowithdi.adapter.DoctorListAdapter +import com.ketub4.mvvmdemowithdi.adapter.IDoctorListAdapter +import com.ketub4.mvvmdemowithdi.databinding.FragmentHomeBinding +import com.ketub4.mvvmdemowithdi.databinding.FragmentSearchBinding +import com.ketub4.mvvmdemowithdi.model.Doctors +import com.ketub4.mvvmdemowithdi.viewModel.CustomViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +class SearchFragment : Fragment(), IDoctorListAdapter { + private var _binding: FragmentSearchBinding?=null + private val binding: FragmentSearchBinding get() = _binding!! + private val customViewModel: CustomViewModel by activityViewModels() + lateinit var doctorListAdapter:DoctorListAdapter + lateinit var doctorList: ArrayList + private val gson = Gson() + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + _binding = FragmentSearchBinding.inflate(layoutInflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + showHideProgressBar() + + customViewModel.getDoctorsList(0) + GlobalScope.launch(Dispatchers.Main) { + delay(5000) + customViewModel.doctorsList.observe(requireActivity(), Observer { list -> + Log.i("doctors=", "doctors=${list.size}") + doctorList = list + if (list.size>0) + showHideProgressBar() + }) + setupRV() + } + + } + + private fun setupRV() { + doctorListAdapter = DoctorListAdapter(doctorList, this, requireActivity()) + binding.recyclerView.apply { + layoutManager = LinearLayoutManager(requireActivity()) + hasFixedSize() + adapter = doctorListAdapter + } + + } + + private fun showHideProgressBar() { + if (_binding!!.progressBar.visibility== View.VISIBLE){ + _binding!!.progressBar.visibility = View.GONE + }else{ + _binding!!.progressBar.visibility = View.VISIBLE + } + + } + + override fun onBookBtnClick(doctor: Doctors) { + val intent = Intent(requireActivity(), BookAppointmentActivity::class.java) + val objString = gson.toJson(doctor) + intent.putExtra("doctorObj",objString) + startActivity(intent) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Appointment.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Appointment.kt new file mode 100644 index 0000000..c6abe1d --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Appointment.kt @@ -0,0 +1,14 @@ +package com.ketub4.mvvmdemowithdi.model + +data class Appointment( + val id: Int, + val doctorId: Int, + val categoryId: Int, + val timeSlot: String, + val date: String, + val time: String, + val booked: Boolean + +) { + constructor(): this(0,0,0,"","","", false) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Category.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Category.kt new file mode 100644 index 0000000..798629e --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Category.kt @@ -0,0 +1,10 @@ +package com.ketub4.mvvmdemowithdi.model + +data class Category(val id: Int, + val name: String, + val description: String){ + + constructor(): this( + 0,"","" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Doctors.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Doctors.kt new file mode 100644 index 0000000..9ca4665 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Doctors.kt @@ -0,0 +1,16 @@ +package com.ketub4.mvvmdemowithdi.model + +data class Doctors( + val category_id: Int, + val id: Int, + val category: String, + val name: String, + val address: String, + val distance: String, + val rating: Int, + +) { + constructor(): this( + 0,0,"","","","",0 + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/model/MovieResult.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/MovieResult.kt new file mode 100644 index 0000000..57c69e0 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/MovieResult.kt @@ -0,0 +1,8 @@ +package com.ketub4.mvvmdemowithdi.model + +data class MovieResult( + val page: Int, + val results: List, + val total_pages: Int, + val total_results: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Notification.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Notification.kt new file mode 100644 index 0000000..742f750 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Notification.kt @@ -0,0 +1,15 @@ +package com.ketub4.mvvmdemowithdi.model + +data class Notification( + val id: Int, + val categoryId: Int, + val categoryName: String, + val title:String, + val message: String, + val date: String, + +) { + constructor(): this( + 0,0,"","","","" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Result.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Result.kt new file mode 100644 index 0000000..6dddfd1 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/model/Result.kt @@ -0,0 +1,18 @@ +package com.ketub4.mvvmdemowithdi.model + +data class Result( + val adult: Boolean, + val backdrop_path: String, + val genre_ids: List, + val id: Int, + val original_language: String, + val original_title: String, + val overview: String, + val popularity: Double, + val poster_path: String, + val release_date: String, + val title: String, + val video: Boolean, + val vote_average: Double, + val vote_count: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/network/APIService.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/network/APIService.kt new file mode 100644 index 0000000..03afa8c --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/network/APIService.kt @@ -0,0 +1,12 @@ +package com.ketub4.mvvmdemowithdi.network + +import com.ketub4.mvvmdemowithdi.model.MovieResult +import com.ketub4.mvvmdemowithdi.utils.Constant +import retrofit2.http.GET + +interface APIService { + + @GET("/3/movie/popular?api_key="+Constant.API_KEY) + suspend fun getListofMovies():MovieResult + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/network/FirebaseService.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/network/FirebaseService.kt new file mode 100644 index 0000000..b54a09d --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/network/FirebaseService.kt @@ -0,0 +1,5 @@ +package com.ketub4.mvvmdemowithdi.network + +interface FirebaseService { + suspend fun onGetCategoryListFetch() +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/repository/MovieRepository.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/repository/MovieRepository.kt new file mode 100644 index 0000000..bff0842 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/repository/MovieRepository.kt @@ -0,0 +1,574 @@ +package com.ketub4.mvvmdemowithdi.repository + +import android.content.Context +import android.util.Log +import com.google.firebase.firestore.FirebaseFirestore +import com.google.firebase.firestore.Query +import com.ketub4.mvvmdemowithdi.model.* +import com.ketub4.mvvmdemowithdi.network.APIService +import com.ketub4.mvvmdemowithdi.network.FirebaseService +import javax.inject.Inject + + +class MovieRepository @Inject constructor(private val apiService: APIService, + private val firebaseDB: FirebaseFirestore, + private val context: Context + +) { + + + + suspend fun getMovieList():MovieResult{ + return apiService.getListofMovies() + } + + fun insertData(){ + firebaseDB.collection("Categories") + .add(Category(8,"Nutritionist ","Be healthy")) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + + } + fun insertDoctorData(){ + + firebaseDB.collection("TimeSlots") + .add(Appointment(1,1,1,"m","22/02/2022","9.30",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(2,1,1,"m","22/02/2022","9.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(3,1,1,"m","22/02/2022","10.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(4,1,1,"m","22/02/2022","10.15",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(5,1,1,"m","22/02/2022","10.30",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(6,1,1,"m","22/02/2022","10.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(7,1,1,"m","22/02/2022","11.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(8,1,1,"m","22/02/2022","11.15",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(9,1,1,"m","22/02/2022","11.30",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + + firebaseDB.collection("TimeSlots") + .add(Appointment(10,1,1,"m","22/02/2022","11.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(11,1,1,"m","22/02/2022","12.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + + //////////////////////////////////////////////////////////////////// + + firebaseDB.collection("TimeSlots") + .add(Appointment(12,1,1,"a","22/02/2022","12.15",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(13,1,1,"a","22/02/2022","12.30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(14,1,1,"a","22/02/2022","12.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(15,1,1,"a","22/02/2022","01.00",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(16,1,1,"a","22/02/2022","01.15",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(17,1,1,"a","22/02/2022","01.30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(18,1,1,"a","22/02/2022","01.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(19,1,1,"a","22/02/2022","02.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(20,1,1,"a","22/02/2022","02.15",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + + firebaseDB.collection("TimeSlots") + .add(Appointment(21,1,1,"a","22/02/2022","02,30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(22,1,1,"a","22/02/2022","02.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(23,1,1,"a","22/02/2022","03.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(24,1,1,"a","22/02/2022","03.15",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(25,1,1,"a","22/02/2022","03.30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(26,1,1,"a","22/02/2022","03.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(27,1,1,"a","22/02/2022","04.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + + //////////////////////////////////////////////////////////////////// + + firebaseDB.collection("TimeSlots") + .add(Appointment(28,1,1,"e","22/02/2022","06.15",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(29,1,1,"e","22/02/2022","06.30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(30,1,1,"e","22/02/2022","06.45",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(31,1,1,"e","22/02/2022","07.00",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(32,1,1,"e","22/02/2022","07.15",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(33,1,1,"e","22/02/2022","07.30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(34,1,1,"e","22/02/2022","07.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(35,1,1,"e","22/02/2022","08.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(36,1,1,"e","22/02/2022","08.15",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + + firebaseDB.collection("TimeSlots") + .add(Appointment(37,1,1,"e","22/02/2022","08,30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(38,1,1,"e","22/02/2022","08.45",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(39,1,1,"e","22/02/2022","09.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(40,1,1,"e","22/02/2022","09.15",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(41,1,1,"e","22/02/2022","09.30",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(42,1,1,"e","22/02/2022","09.45",true)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + firebaseDB.collection("TimeSlots") + .add(Appointment(43,1,1,"e","22/02/2022","10.00",false)) + + .addOnSuccessListener { + Log.i("Successful","Addition of Record") + } + .addOnFailureListener { + Log.i("Error","Adding Record") + } + + + + } + + fun getCategoryList():ArrayList{ + var categoryList = ArrayList() + firebaseDB.collection("Categories") + .orderBy("id", Query.Direction.ASCENDING) + .get() + .addOnSuccessListener { results-> + + for (document in results){ + categoryList.add(document.toObject(Category::class.java)) + } + Log.i("Successful","Fetching of Record") + + } + .addOnFailureListener { + Log.i("Error","Fetching Record") + } + + return categoryList + } + + suspend fun getDoctorList(category_id: Int):ArrayList{ + Log.i("category_id", "category_id=$category_id") + var doctorList = ArrayList() + val collection = firebaseDB.collection("Doctors") + var collectionReference:Query = collection + if (category_id!=0){ + collectionReference = collection.whereEqualTo("category_id", category_id) + } + + collectionReference.orderBy("id", Query.Direction.ASCENDING) + .get() + .addOnSuccessListener { result-> + for (document in result){ + doctorList.add(document.toObject(Doctors::class.java)) + } + Log.i("Successful","Fetching of Doctors Record") + + } + + .addOnFailureListener { + Log.i("Error","Fetching Doctors Record") + } + + return doctorList + } + + suspend fun getNotifications():ArrayList{ + var notificationList = ArrayList() + val collection = firebaseDB.collection("Notifications") + collection.orderBy("id", Query.Direction.ASCENDING) + .get() + .addOnSuccessListener { result-> + for (document in result){ + notificationList.add(document.toObject(Notification::class.java)) + } + Log.i("Successful","Fetching of notificationList Record") + + } + + .addOnFailureListener { + Log.i("Error","Fetching notificationList Record") + } + + return notificationList + } + + suspend fun getTimeSlots(date:String, doctorId: Int):ArrayList{ + var timeSlotList = ArrayList() + val collection = firebaseDB.collection("TimeSlots") + var query = collection.whereEqualTo("date","22/02/2022")// hardcoded for demo + //query = query.whereEqualTo(doctorId,1)//later add doctor Id filter + query + .orderBy("id", Query.Direction.ASCENDING) + .get() + .addOnSuccessListener { result-> + for (document in result){ + timeSlotList.add(document.toObject(Appointment::class.java)) + } + Log.i("Successful","Fetching of getTimeSlots Record") + + } + + .addOnFailureListener { + Log.i("Error","Fetching getTimeSlots Record") + } + + return timeSlotList + } + + +// suspend fun getTimeSlots():ArrayList{ +//// var appointmentList = ArrayList() +//// appointmentList.add(Appointment(1, "m", "22/02/2022","9.30",false)) +//// appointmentList.add(Appointment(2, "10.30",false)) +//// appointmentList.add(Appointment(3, "11.30",true)) +//// appointmentList.add(Appointment(4, "12.30",false)) +//// appointmentList.add(Appointment(5, "01.30",false)) +//// appointmentList.add(Appointment(6, "02.30",true)) +//// appointmentList.add(Appointment(7, "03.30",false)) +//// appointmentList.add(Appointment(9, "09.30",false)) +//// appointmentList.add(Appointment(10, "10.30",false)) +//// appointmentList.add(Appointment(11, "11.30",true)) +//// appointmentList.add(Appointment(12, "12.30",false)) +//// appointmentList.add(Appointment(13, "01.30",false)) +//// appointmentList.add(Appointment(14, "02.30",true)) +//// appointmentList.add(Appointment(15, "03.30",false)) +//// appointmentList.add(Appointment(16, "09.30",false)) +//// appointmentList.add(Appointment(17, "10.30",false)) +//// appointmentList.add(Appointment(18, "11.30",true)) +//// appointmentList.add(Appointment(19, "12.30",false)) +//// appointmentList.add(Appointment(20, "31.30",false)) +//// appointmentList.add(Appointment(21, "32.30",true)) +//// appointmentList.add(Appointment(22, "33.30",false)) +//// val collection = firebaseDB.collection("TimeSlots") +//// collection.orderBy("id", Query.Direction.ASCENDING) +//// .get() +//// .addOnSuccessListener { result-> +//// for (document in result){ +//// notificationList.add(document.toObject(Notification::class.java)) +//// } +//// Log.i("Successful","Fetching of notificationList Record") +//// +//// } +//// +//// .addOnFailureListener { +//// Log.i("Error","Fetching notificationList Record") +//// } +// +// return appointmentList +// } + + + +} + diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/utils/CalendarUtils.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/utils/CalendarUtils.kt new file mode 100644 index 0000000..dc33293 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/utils/CalendarUtils.kt @@ -0,0 +1,75 @@ +package com.ketub4.mvvmdemowithdi.utils + +import android.os.Build +import androidx.annotation.RequiresApi +import java.time.DayOfWeek +import java.time.LocalDate + +import java.time.LocalTime +import java.time.YearMonth +import java.time.format.DateTimeFormatter +import java.util.ArrayList + +class CalendarUtils { + + companion object{ + + @RequiresApi(Build.VERSION_CODES.O) + var selectedDate: LocalDate = LocalDate.now() + + @RequiresApi(Build.VERSION_CODES.O) + fun formattedDate(date: LocalDate): String? { + val formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy") + return date.format(formatter) + } + @RequiresApi(Build.VERSION_CODES.O) + fun formattedTime(time: LocalTime): String? { + val formatter = DateTimeFormatter.ofPattern("hh:mm:ss a") + return time.format(formatter) + } + @RequiresApi(Build.VERSION_CODES.O) + fun monthYearFromDate(date: LocalDate): String? { + val formatter = DateTimeFormatter.ofPattern("MMMM yyyy") + return date.format(formatter) + } + @RequiresApi(Build.VERSION_CODES.O) + fun daysInMonthArray(date: LocalDate?): ArrayList? { + val daysInMonthArray = ArrayList() + val yearMonth = YearMonth.from(date) + val daysInMonth = yearMonth.lengthOfMonth() + val firstOfMonth: LocalDate = this.selectedDate!!.withDayOfMonth(1) + val dayOfWeek = firstOfMonth.dayOfWeek.value + for (i in 1..42) { + if (i <= dayOfWeek || i > daysInMonth + dayOfWeek) daysInMonthArray.add(null) else daysInMonthArray.add( + LocalDate.of( + this.selectedDate!!.year, + this.selectedDate!!.month, + i - dayOfWeek + ) + ) + } + return daysInMonthArray + } + @RequiresApi(Build.VERSION_CODES.O) + fun daysInWeekArray(selectedDate: LocalDate): ArrayList { + val days = ArrayList() + var current = sundayForDate(selectedDate) + val endDate = current!!.plusWeeks(1) + while (current!!.isBefore(endDate)) { + days.add(current) + current = current.plusDays(1) + } + return days + } + @RequiresApi(Build.VERSION_CODES.O) + private fun sundayForDate(current: LocalDate): LocalDate? { + var current = current + val oneWeekAgo = current.minusWeeks(1) + while (current.isAfter(oneWeekAgo)) { + if (current.dayOfWeek == DayOfWeek.SUNDAY) return current + current = current.minusDays(1) + } + return null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/utils/Constant.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/utils/Constant.kt new file mode 100644 index 0000000..7ca7012 --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/utils/Constant.kt @@ -0,0 +1,10 @@ +package com.ketub4.mvvmdemowithdi.utils + +class Constant { + + companion object{ + const val BASE_URL ="https://api.themoviedb.org" + const val API_KEY = "70b3c31685d50c114975c4fffba51594" + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ketub4/mvvmdemowithdi/viewModel/CustomViewModel.kt b/app/src/main/java/com/ketub4/mvvmdemowithdi/viewModel/CustomViewModel.kt new file mode 100644 index 0000000..467db1a --- /dev/null +++ b/app/src/main/java/com/ketub4/mvvmdemowithdi/viewModel/CustomViewModel.kt @@ -0,0 +1,76 @@ +package com.ketub4.mvvmdemowithdi.viewModel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ketub4.mvvmdemowithdi.model.* +import com.ketub4.mvvmdemowithdi.network.FirebaseService +import com.ketub4.mvvmdemowithdi.repository.MovieRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class CustomViewModel @Inject constructor(private val repository: MovieRepository) :ViewModel() { + + private var _movieList =MutableLiveData>() + val movieList: LiveData> get()= _movieList + + var _categoryList =MutableLiveData>() + val categoryList: LiveData> get()= _categoryList + + private var _doctorsList =MutableLiveData>() + val doctorsList: LiveData> get()= _doctorsList + + private var _notificationsList =MutableLiveData>() + val notificationsList: LiveData> get()= _notificationsList + + private var _timeSlotList =MutableLiveData>() + val timeSlotList: LiveData> get()= _timeSlotList + + fun getMovieData(){ + viewModelScope.launch { + _movieList.postValue(repository.getMovieList().results) + } + } + + fun insertRecords(){ + viewModelScope.launch { + repository.insertData() + } + } + fun insertDoctorData(){ + viewModelScope.launch { + repository.insertDoctorData() + } + } + + fun getCategoryList(){ + //viewModelScope.launch(Dispatchers.Main) { + _categoryList.postValue(repository.getCategoryList()) + //_categoryList.value = + //_categoryList.value = repository.getCategoryList() + //} + } + + fun getDoctorsList(category_id: Int){ + viewModelScope.launch { + _doctorsList.postValue(repository.getDoctorList(category_id)) + } + } + + fun getNotifications(){ + viewModelScope.launch { + _notificationsList.postValue(repository.getNotifications()) + } + } + + fun getTimeSlots(date:String, doctorId: Int){ + viewModelScope.launch { + _timeSlotList.postValue(repository.getTimeSlots(date, doctorId)) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/address.png b/app/src/main/res/drawable-v24/address.png new file mode 100644 index 0000000..82b6b3f Binary files /dev/null and b/app/src/main/res/drawable-v24/address.png differ diff --git a/app/src/main/res/drawable-v24/afternoon.png b/app/src/main/res/drawable-v24/afternoon.png new file mode 100644 index 0000000..a1198ad Binary files /dev/null and b/app/src/main/res/drawable-v24/afternoon.png differ diff --git a/app/src/main/res/drawable-v24/back_arrow.png b/app/src/main/res/drawable-v24/back_arrow.png new file mode 100644 index 0000000..6267b23 Binary files /dev/null and b/app/src/main/res/drawable-v24/back_arrow.png differ diff --git a/app/src/main/res/drawable-v24/banner_image1.png b/app/src/main/res/drawable-v24/banner_image1.png new file mode 100644 index 0000000..67654be Binary files /dev/null and b/app/src/main/res/drawable-v24/banner_image1.png differ diff --git a/app/src/main/res/drawable-v24/banner_image2.png b/app/src/main/res/drawable-v24/banner_image2.png new file mode 100644 index 0000000..67654be Binary files /dev/null and b/app/src/main/res/drawable-v24/banner_image2.png differ diff --git a/app/src/main/res/drawable-v24/calendar.png b/app/src/main/res/drawable-v24/calendar.png new file mode 100644 index 0000000..5488f9f Binary files /dev/null and b/app/src/main/res/drawable-v24/calendar.png differ diff --git a/app/src/main/res/drawable-v24/cat_1.png b/app/src/main/res/drawable-v24/cat_1.png new file mode 100644 index 0000000..df4ed09 Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_1.png differ diff --git a/app/src/main/res/drawable-v24/cat_10.png b/app/src/main/res/drawable-v24/cat_10.png new file mode 100644 index 0000000..d015496 Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_10.png differ diff --git a/app/src/main/res/drawable-v24/cat_2.png b/app/src/main/res/drawable-v24/cat_2.png new file mode 100644 index 0000000..060184f Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_2.png differ diff --git a/app/src/main/res/drawable-v24/cat_3.png b/app/src/main/res/drawable-v24/cat_3.png new file mode 100644 index 0000000..a150374 Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_3.png differ diff --git a/app/src/main/res/drawable-v24/cat_4.png b/app/src/main/res/drawable-v24/cat_4.png new file mode 100644 index 0000000..3ee0980 Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_4.png differ diff --git a/app/src/main/res/drawable-v24/cat_5.png b/app/src/main/res/drawable-v24/cat_5.png new file mode 100644 index 0000000..a76dcaa Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_5.png differ diff --git a/app/src/main/res/drawable-v24/cat_6.png b/app/src/main/res/drawable-v24/cat_6.png new file mode 100644 index 0000000..48dac43 Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_6.png differ diff --git a/app/src/main/res/drawable-v24/cat_7.png b/app/src/main/res/drawable-v24/cat_7.png new file mode 100644 index 0000000..9138677 Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_7.png differ diff --git a/app/src/main/res/drawable-v24/cat_8.png b/app/src/main/res/drawable-v24/cat_8.png new file mode 100644 index 0000000..bde42b8 Binary files /dev/null and b/app/src/main/res/drawable-v24/cat_8.png differ diff --git a/app/src/main/res/drawable-v24/dob.png b/app/src/main/res/drawable-v24/dob.png new file mode 100644 index 0000000..6f15daf Binary files /dev/null and b/app/src/main/res/drawable-v24/dob.png differ diff --git a/app/src/main/res/drawable-v24/doc_f1.png b/app/src/main/res/drawable-v24/doc_f1.png new file mode 100644 index 0000000..8e676e1 Binary files /dev/null and b/app/src/main/res/drawable-v24/doc_f1.png differ diff --git a/app/src/main/res/drawable-v24/doc_f2.png b/app/src/main/res/drawable-v24/doc_f2.png new file mode 100644 index 0000000..0762280 Binary files /dev/null and b/app/src/main/res/drawable-v24/doc_f2.png differ diff --git a/app/src/main/res/drawable-v24/doc_m1.png b/app/src/main/res/drawable-v24/doc_m1.png new file mode 100644 index 0000000..8378158 Binary files /dev/null and b/app/src/main/res/drawable-v24/doc_m1.png differ diff --git a/app/src/main/res/drawable-v24/doc_m2.png b/app/src/main/res/drawable-v24/doc_m2.png new file mode 100644 index 0000000..29c52f4 Binary files /dev/null and b/app/src/main/res/drawable-v24/doc_m2.png differ diff --git a/app/src/main/res/drawable-v24/doc_m3.png b/app/src/main/res/drawable-v24/doc_m3.png new file mode 100644 index 0000000..03ed336 Binary files /dev/null and b/app/src/main/res/drawable-v24/doc_m3.png differ diff --git a/app/src/main/res/drawable-v24/down_arrow.png b/app/src/main/res/drawable-v24/down_arrow.png new file mode 100644 index 0000000..6c52d57 Binary files /dev/null and b/app/src/main/res/drawable-v24/down_arrow.png differ diff --git a/app/src/main/res/drawable-v24/edit.png b/app/src/main/res/drawable-v24/edit.png new file mode 100644 index 0000000..5cb993c Binary files /dev/null and b/app/src/main/res/drawable-v24/edit.png differ diff --git a/app/src/main/res/drawable-v24/email.png b/app/src/main/res/drawable-v24/email.png new file mode 100644 index 0000000..24e5989 Binary files /dev/null and b/app/src/main/res/drawable-v24/email.png differ diff --git a/app/src/main/res/drawable-v24/error.png b/app/src/main/res/drawable-v24/error.png new file mode 100644 index 0000000..0c5d33b Binary files /dev/null and b/app/src/main/res/drawable-v24/error.png differ diff --git a/app/src/main/res/drawable-v24/failed.png b/app/src/main/res/drawable-v24/failed.png new file mode 100644 index 0000000..844c8a8 Binary files /dev/null and b/app/src/main/res/drawable-v24/failed.png differ diff --git a/app/src/main/res/drawable-v24/general.png b/app/src/main/res/drawable-v24/general.png new file mode 100644 index 0000000..c99063d Binary files /dev/null and b/app/src/main/res/drawable-v24/general.png differ diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/left_arrow.png b/app/src/main/res/drawable-v24/left_arrow.png new file mode 100644 index 0000000..1ae2f34 Binary files /dev/null and b/app/src/main/res/drawable-v24/left_arrow.png differ diff --git a/app/src/main/res/drawable-v24/logout.png b/app/src/main/res/drawable-v24/logout.png new file mode 100644 index 0000000..3bf6511 Binary files /dev/null and b/app/src/main/res/drawable-v24/logout.png differ diff --git a/app/src/main/res/drawable-v24/menu.png b/app/src/main/res/drawable-v24/menu.png new file mode 100644 index 0000000..31f956a Binary files /dev/null and b/app/src/main/res/drawable-v24/menu.png differ diff --git a/app/src/main/res/drawable-v24/morning.png b/app/src/main/res/drawable-v24/morning.png new file mode 100644 index 0000000..e12f4df Binary files /dev/null and b/app/src/main/res/drawable-v24/morning.png differ diff --git a/app/src/main/res/drawable-v24/name.png b/app/src/main/res/drawable-v24/name.png new file mode 100644 index 0000000..d68ea7f Binary files /dev/null and b/app/src/main/res/drawable-v24/name.png differ diff --git a/app/src/main/res/drawable-v24/next.png b/app/src/main/res/drawable-v24/next.png new file mode 100644 index 0000000..f8f80da Binary files /dev/null and b/app/src/main/res/drawable-v24/next.png differ diff --git a/app/src/main/res/drawable-v24/next_new.png b/app/src/main/res/drawable-v24/next_new.png new file mode 100644 index 0000000..55c3b62 Binary files /dev/null and b/app/src/main/res/drawable-v24/next_new.png differ diff --git a/app/src/main/res/drawable-v24/night.png b/app/src/main/res/drawable-v24/night.png new file mode 100644 index 0000000..9ac8fc9 Binary files /dev/null and b/app/src/main/res/drawable-v24/night.png differ diff --git a/app/src/main/res/drawable-v24/previous.png b/app/src/main/res/drawable-v24/previous.png new file mode 100644 index 0000000..ecbb39f Binary files /dev/null and b/app/src/main/res/drawable-v24/previous.png differ diff --git a/app/src/main/res/drawable-v24/profile_image.png b/app/src/main/res/drawable-v24/profile_image.png new file mode 100644 index 0000000..c789dfc Binary files /dev/null and b/app/src/main/res/drawable-v24/profile_image.png differ diff --git a/app/src/main/res/drawable-v24/right.png b/app/src/main/res/drawable-v24/right.png new file mode 100644 index 0000000..268744f Binary files /dev/null and b/app/src/main/res/drawable-v24/right.png differ diff --git a/app/src/main/res/drawable-v24/rounded_shape.xml b/app/src/main/res/drawable-v24/rounded_shape.xml new file mode 100644 index 0000000..bc1eed2 --- /dev/null +++ b/app/src/main/res/drawable-v24/rounded_shape.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/share.png b/app/src/main/res/drawable-v24/share.png new file mode 100644 index 0000000..7692eea Binary files /dev/null and b/app/src/main/res/drawable-v24/share.png differ diff --git a/app/src/main/res/drawable-v24/subscribe.png b/app/src/main/res/drawable-v24/subscribe.png new file mode 100644 index 0000000..48e9054 Binary files /dev/null and b/app/src/main/res/drawable-v24/subscribe.png differ diff --git a/app/src/main/res/drawable-v24/success.png b/app/src/main/res/drawable-v24/success.png new file mode 100644 index 0000000..95cf217 Binary files /dev/null and b/app/src/main/res/drawable-v24/success.png differ diff --git a/app/src/main/res/drawable-v24/three_dot_menu.png b/app/src/main/res/drawable-v24/three_dot_menu.png new file mode 100644 index 0000000..a1b6c0b Binary files /dev/null and b/app/src/main/res/drawable-v24/three_dot_menu.png differ diff --git a/app/src/main/res/drawable-v24/welcome.png b/app/src/main/res/drawable-v24/welcome.png new file mode 100644 index 0000000..93c833c Binary files /dev/null and b/app/src/main/res/drawable-v24/welcome.png differ diff --git a/app/src/main/res/drawable/back.xml b/app/src/main/res/drawable/back.xml new file mode 100644 index 0000000..bcc4ebb --- /dev/null +++ b/app/src/main/res/drawable/back.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/background_shape.xml b/app/src/main/res/drawable/background_shape.xml new file mode 100644 index 0000000..5aca057 --- /dev/null +++ b/app/src/main/res/drawable/background_shape.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_shape1.xml b/app/src/main/res/drawable/background_shape1.xml new file mode 100644 index 0000000..b261564 --- /dev/null +++ b/app/src/main/res/drawable/background_shape1.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_shape2.xml b/app/src/main/res/drawable/background_shape2.xml new file mode 100644 index 0000000..6bc3d6f --- /dev/null +++ b/app/src/main/res/drawable/background_shape2.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_shape_blue.xml b/app/src/main/res/drawable/background_shape_blue.xml new file mode 100644 index 0000000..dfe61f0 --- /dev/null +++ b/app/src/main/res/drawable/background_shape_blue.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_shape_gray.xml b/app/src/main/res/drawable/background_shape_gray.xml new file mode 100644 index 0000000..a8a3de9 --- /dev/null +++ b/app/src/main/res/drawable/background_shape_gray.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_shape_green.xml b/app/src/main/res/drawable/background_shape_green.xml new file mode 100644 index 0000000..f038119 --- /dev/null +++ b/app/src/main/res/drawable/background_shape_green.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_shape_square_blue.xml b/app/src/main/res/drawable/background_shape_square_blue.xml new file mode 100644 index 0000000..1f3fa66 --- /dev/null +++ b/app/src/main/res/drawable/background_shape_square_blue.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/background_shape_white.xml b/app/src/main/res/drawable/background_shape_white.xml new file mode 100644 index 0000000..4f242dd --- /dev/null +++ b/app/src/main/res/drawable/background_shape_white.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/banner_image1.png b/app/src/main/res/drawable/banner_image1.png new file mode 100644 index 0000000..ddc870d Binary files /dev/null and b/app/src/main/res/drawable/banner_image1.png differ diff --git a/app/src/main/res/drawable/banner_image2.png b/app/src/main/res/drawable/banner_image2.png new file mode 100644 index 0000000..ddc870d Binary files /dev/null and b/app/src/main/res/drawable/banner_image2.png differ diff --git a/app/src/main/res/drawable/home.png b/app/src/main/res/drawable/home.png new file mode 100644 index 0000000..876ed68 Binary files /dev/null and b/app/src/main/res/drawable/home.png differ diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/location.xml b/app/src/main/res/drawable/location.xml new file mode 100644 index 0000000..1e53e2c --- /dev/null +++ b/app/src/main/res/drawable/location.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/notification.png b/app/src/main/res/drawable/notification.png new file mode 100644 index 0000000..96b3caf Binary files /dev/null and b/app/src/main/res/drawable/notification.png differ diff --git a/app/src/main/res/drawable/profile.png b/app/src/main/res/drawable/profile.png new file mode 100644 index 0000000..4052481 Binary files /dev/null and b/app/src/main/res/drawable/profile.png differ diff --git a/app/src/main/res/drawable/search.png b/app/src/main/res/drawable/search.png new file mode 100644 index 0000000..a75718d Binary files /dev/null and b/app/src/main/res/drawable/search.png differ diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml new file mode 100644 index 0000000..6d81870 --- /dev/null +++ b/app/src/main/res/drawable/side_nav_bar.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/start.xml b/app/src/main/res/drawable/start.xml new file mode 100644 index 0000000..82b9e33 --- /dev/null +++ b/app/src/main/res/drawable/start.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/start_filled.xml b/app/src/main/res/drawable/start_filled.xml new file mode 100644 index 0000000..380f917 --- /dev/null +++ b/app/src/main/res/drawable/start_filled.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_appointment_details.xml b/app/src/main/res/layout/activity_appointment_details.xml new file mode 100644 index 0000000..bc6461f --- /dev/null +++ b/app/src/main/res/layout/activity_appointment_details.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +