├── .gitignore ├── .idea ├── .gitignore ├── runConfigurations.xml └── runConfigurations │ ├── atm.xml │ ├── payment_due.xml │ ├── slice.xml │ ├── slice_make_reservation.xml │ ├── slice_rate_reservation.xml │ └── slice_reservation.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── captech │ │ └── android │ │ └── demos │ │ └── slices │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── captech │ │ │ └── android │ │ │ └── demos │ │ │ └── slices │ │ │ ├── MainActivity.kt │ │ │ ├── MessageHotelActivity.kt │ │ │ ├── SeeMoreHotelsActivity.kt │ │ │ ├── SendMoneyActivity.kt │ │ │ ├── SlicesApplication.kt │ │ │ ├── ViewHotelActivity.kt │ │ │ ├── data │ │ │ ├── model │ │ │ │ └── Hotel.kt │ │ │ └── repository │ │ │ │ └── HotelRepository.kt │ │ │ ├── provider │ │ │ ├── BankSliceProvider.kt │ │ │ ├── ContentUris.kt │ │ │ └── HotelSliceProvider.kt │ │ │ ├── receiver │ │ │ └── HotelsBroadcastReceiver.kt │ │ │ ├── state │ │ │ └── AppState.kt │ │ │ ├── ui │ │ │ ├── main │ │ │ │ ├── MainFragment.kt │ │ │ │ └── MainViewModel.kt │ │ │ ├── messagehotel │ │ │ │ ├── MessageHotelFragment.kt │ │ │ │ └── MessageHotelViewModel.kt │ │ │ ├── seemorehotels │ │ │ │ ├── SeeMoreHotelsFragment.kt │ │ │ │ └── SeeMoreHotelsViewModel.kt │ │ │ └── viewhotel │ │ │ │ ├── ViewHotelFragment.kt │ │ │ │ └── ViewHotelViewModel.kt │ │ │ └── util │ │ │ └── HotelUtils.kt │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_hotel_01.png │ │ ├── ic_hotel_02.png │ │ ├── ic_hotel_03.png │ │ ├── ic_hotel_04.png │ │ ├── ic_hotel_05.png │ │ ├── ic_hotel_06.png │ │ └── ic_hotel_07.png │ │ ├── drawable-mdpi │ │ ├── ic_hotel_01.png │ │ ├── ic_hotel_02.png │ │ ├── ic_hotel_03.png │ │ ├── ic_hotel_04.png │ │ ├── ic_hotel_05.png │ │ ├── ic_hotel_06.png │ │ └── ic_hotel_07.png │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xhdpi │ │ ├── ic_hotel_01.png │ │ ├── ic_hotel_02.png │ │ ├── ic_hotel_03.png │ │ ├── ic_hotel_04.png │ │ ├── ic_hotel_05.png │ │ ├── ic_hotel_06.png │ │ └── ic_hotel_07.png │ │ ├── drawable-xxhdpi │ │ ├── ic_hotel_01.png │ │ ├── ic_hotel_02.png │ │ ├── ic_hotel_03.png │ │ ├── ic_hotel_04.png │ │ ├── ic_hotel_05.png │ │ ├── ic_hotel_06.png │ │ └── ic_hotel_07.png │ │ ├── drawable-xxxhdpi │ │ ├── ic_hotel_01.png │ │ ├── ic_hotel_02.png │ │ ├── ic_hotel_03.png │ │ ├── ic_hotel_04.png │ │ ├── ic_hotel_05.png │ │ ├── ic_hotel_06.png │ │ └── ic_hotel_07.png │ │ ├── drawable │ │ ├── bank.xml │ │ ├── ic_directions.xml │ │ ├── ic_forum.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_map_marker.xml │ │ ├── ic_map_marker_distance.xml │ │ ├── ic_marker_check.xml │ │ ├── ic_more.xml │ │ ├── ic_send_money.xml │ │ ├── ic_sort_ascending.xml │ │ ├── ic_sort_descending.xml │ │ ├── ic_sort_price.xml │ │ ├── ic_star.xml │ │ └── ic_star_filled.xml │ │ ├── ic_hotel_01.zip │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_message_hotel.xml │ │ ├── activity_see_more_hotels.xml │ │ ├── activity_send_money.xml │ │ ├── activity_view_hotel.xml │ │ ├── fragment_main.xml │ │ ├── fragment_message_hotel.xml │ │ ├── fragment_see_more_hotels.xml │ │ └── fragment_view_hotel.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── res │ │ ├── drawable-hdpi │ │ │ └── ic_hotel_01.png │ │ ├── drawable-mdpi │ │ │ └── ic_hotel_01.png │ │ ├── drawable-xhdpi │ │ │ └── ic_hotel_01.png │ │ ├── drawable-xxhdpi │ │ │ └── ic_hotel_01.png │ │ └── drawable-xxxhdpi │ │ │ └── ic_hotel_01.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── captech │ └── android │ └── demos │ └── slices │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── app-demo.gif ├── bank_slices.png ├── hotel_slices_01.png └── hotel_slices_02.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | ##### MAC OS X ##### 2 | 3 | .DS_Store 4 | 5 | ##### JAVA ##### 6 | 7 | # Java class files 8 | *.class 9 | 10 | # Generated files 11 | bin/ 12 | gen/ 13 | out/ 14 | *.log 15 | 16 | 17 | ##### ANDROID ##### 18 | 19 | # Built application files 20 | *.apk 21 | *.ap_ 22 | 23 | # Files for the dex VM 24 | *.dex 25 | 26 | # Keystore files 27 | *.jks 28 | *.keystore 29 | signing-*.properties 30 | !signing-debug.properties 31 | 32 | ##### GRADLE ##### 33 | 34 | # Gradle files 35 | .gradle/ 36 | build/ 37 | */build 38 | 39 | 40 | ##### ANDROID STUDIO ##### 41 | 42 | # Android Studio files 43 | *.iml 44 | captures/ 45 | .navigation/ 46 | 47 | # Local configuration file (sdk path, etc) 48 | local.properties 49 | 50 | 51 | ##### DON'T IGNORE THESE ###### 52 | !.idea/ 53 | !.idea/runConfigurations/** 54 | !.idea/runConfigurations.xml 55 | 56 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !runConfigurations 4 | !runConfigurations/* 5 | !runConfigurations.xml -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/runConfigurations/atm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | -------------------------------------------------------------------------------- /.idea/runConfigurations/payment_due.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | -------------------------------------------------------------------------------- /.idea/runConfigurations/slice.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | -------------------------------------------------------------------------------- /.idea/runConfigurations/slice_make_reservation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | -------------------------------------------------------------------------------- /.idea/runConfigurations/slice_rate_reservation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | -------------------------------------------------------------------------------- /.idea/runConfigurations/slice_reservation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Google IO - Android Slices Demo 2 | 3 | 4 | by [Jack Hughes](https://github.com/jackovt) and [Alisher Pazylbekov](https://github.com/apazylbekov) 5 | 6 | Slices are templated views that have the ability to show and interact with content from an app from Google Search and later, places like the Google Assistant. This is a demonstration of functionality in a sample hotel and banking application. 7 | 8 | ### Getting Started 9 | To get started, you'll need to get the latest version of Android Studio. At the time of writing this, the latest was [Android Studio 3.2 Canary 14](https://developer.android.com/studio/preview/). In addition, make sure to download the Slice Viewer sample app found on Google's [Getting Started](https://developer.android.com/guide/slices/getting-started) site. The site also provides step by step guides on how to get Slices working on your emulator. 10 | 11 | ### Helpful Tips 12 | - Google has begun repackaging their support library as the "androidx" library, and you'll get the backwards compatibility by using the [androidx library](https://developer.android.com/reference/androidx/slice/Slice) 13 | - the androidx library and the native android Slices do NOT mix, so be careful 14 | - during the creation stage of the project, using the provided Activity & Fragment + ViewModel project set up was very helpful 15 | - when setting up initial SliceProvider, use Android -> New -> Other -> Slice Provider so Android sets up everything for you correctly 16 | - make sure to add any broadcast receivers you create to AndroidManifest.xml 17 | - Slice Viewer occasionally does not update, just force close the Slice Viewer app and run again 18 | - set up the run configurations as recommended in the [Getting Started](https://developer.android.com/guide/slices/getting-started) guide, it made testing slices much easier 19 | - make sure to use latest gradle versions, an easy way to be certain or to find specific dependencies is to look in the [Maven Repository](https://mvnrepository.com/search?q=androidx) 20 | - `implementation 'androidx.slice:slices-core:1.0.0-alpha1'` and `implementation 'androidx.slice:slices-builders:1.0.0-alpha1'` caused builds to fail, make sure to update to `androidx.slice:slice` 21 | 22 | ![App Demo](https://raw.githubusercontent.com/CapTechMobile/Android-Slices/master/screenshots/app-demo.gif) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion 'android-P' 9 | defaultConfig { 10 | applicationId "com.captech.android.demos.slices" 11 | minSdkVersion 'P' 12 | targetSdkVersion 'P' 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | dataBinding { 24 | enabled = true 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 31 | implementation 'androidx.appcompat:appcompat:1.0.0-alpha1' 32 | implementation 'androidx.constraintlayout:constraintlayout:1.1.0' 33 | implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0-alpha1' 34 | implementation 'androidx.annotation:annotation:1.0.0-alpha1' 35 | implementation 'androidx.slice:slice-core:1.0.0-alpha1' 36 | implementation 'androidx.slice:slice-builders:1.0.0-alpha1' 37 | annotationProcessor 'com.android.databinding:compiler:3.1.2' 38 | testImplementation 'junit:junit:4.12' 39 | androidTestImplementation 'androidx.test:runner:1.1.0-alpha1' 40 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha1' 41 | } 42 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/captech/android/demos/slices/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices 2 | 3 | import androidx.test.InstrumentationRegistry 4 | import androidx.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.captech.android.demos.slices", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import android.os.Bundle 5 | import com.captech.android.demos.slices.ui.main.MainFragment 6 | 7 | class MainActivity : AppCompatActivity() { 8 | 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | setContentView(R.layout.activity_main) 12 | if (savedInstanceState == null) { 13 | supportFragmentManager.beginTransaction() 14 | .replace(R.id.container, MainFragment.newInstance()) 15 | .commitNow() 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/MessageHotelActivity.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import android.os.Bundle 5 | import com.captech.android.demos.slices.ui.messagehotel.MessageHotelFragment 6 | 7 | class MessageHotelActivity : AppCompatActivity() { 8 | 9 | companion object { 10 | const val REQUEST_CODE_MESSAGE_HOTEL = 5001 11 | } 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_message_hotel) 16 | if (savedInstanceState == null) { 17 | supportFragmentManager.beginTransaction() 18 | .replace(R.id.container, MessageHotelFragment.newInstance()) 19 | .commitNow() 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/SeeMoreHotelsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import android.os.Bundle 5 | import com.captech.android.demos.slices.ui.seemorehotels.SeeMoreHotelsFragment 6 | 7 | class SeeMoreHotelsActivity : AppCompatActivity() { 8 | 9 | companion object { 10 | const val REQUEST_CODE_SEE_MORE_HOTELS = 4001 11 | } 12 | 13 | override fun onCreate(savedInstanceState: Bundle?) { 14 | super.onCreate(savedInstanceState) 15 | setContentView(R.layout.activity_see_more_hotels) 16 | if (savedInstanceState == null) { 17 | supportFragmentManager.beginTransaction() 18 | .replace(R.id.container, SeeMoreHotelsFragment.newInstance()) 19 | .commitNow() 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/SendMoneyActivity.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import android.os.Bundle 5 | import android.view.View 6 | import android.widget.Button 7 | import android.widget.Toast 8 | 9 | class SendMoneyActivity : AppCompatActivity() { 10 | 11 | override fun onCreate(savedInstanceState: Bundle?) { 12 | super.onCreate(savedInstanceState) 13 | setContentView(R.layout.activity_send_money) 14 | 15 | var makePaymentBtn = findViewById(R.id.makePaymentBtn) as Button 16 | makePaymentBtn.setOnClickListener { 17 | Toast.makeText(this@SendMoneyActivity, "Payment Sent", Toast.LENGTH_SHORT).show() 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/SlicesApplication.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices 2 | 3 | import android.app.Application 4 | import com.captech.android.demos.slices.state.AppState 5 | 6 | class SlicesApplication : Application() { 7 | 8 | lateinit var appState: AppState 9 | 10 | override fun onCreate() { 11 | super.onCreate() 12 | appState = AppState() 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ViewHotelActivity.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.captech.android.demos.slices.data.model.Hotel 6 | import com.captech.android.demos.slices.ui.viewhotel.ViewHotelFragment 7 | 8 | class ViewHotelActivity : AppCompatActivity() { 9 | 10 | companion object { 11 | const val EXTRA_HOTEL: String = "EXTRA_HOTEL" 12 | const val REQUEST_CODE_VIEW_HOTEL: Int = 3001 13 | } 14 | 15 | private lateinit var hotel: Hotel 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_view_hotel) 20 | if (intent != null && intent.hasExtra(EXTRA_HOTEL)) { 21 | hotel = intent.getParcelableExtra(EXTRA_HOTEL) 22 | } 23 | supportFragmentManager.beginTransaction() 24 | .replace(R.id.container, ViewHotelFragment.newInstance(hotel)) 25 | .commitNow() 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/data/model/Hotel.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.data.model 2 | 3 | import android.location.Address 4 | import android.os.Parcel 5 | import android.os.Parcelable 6 | import androidx.annotation.DrawableRes 7 | import java.util.* 8 | 9 | 10 | data class Hotel(val name: String, val ratePerNight: Double, @DrawableRes val imageResId: Int, val address: Address) : Parcelable { 11 | 12 | public constructor() : this("", 0.0, -1, Address(Locale.getDefault())) {} 13 | 14 | constructor(parcel: Parcel) : this( 15 | parcel.readString(), 16 | parcel.readDouble(), 17 | parcel.readInt(), 18 | parcel.readParcelable(Address::class.java.classLoader)) { 19 | } 20 | 21 | override fun writeToParcel(parcel: Parcel, flags: Int) { 22 | parcel.writeString(name) 23 | parcel.writeDouble(ratePerNight) 24 | parcel.writeInt(imageResId) 25 | parcel.writeParcelable(address, flags) 26 | } 27 | 28 | override fun describeContents(): Int { 29 | return 0; 30 | } 31 | 32 | companion object CREATOR : Parcelable.Creator { 33 | override fun createFromParcel(parcel: Parcel): Hotel { 34 | return Hotel(parcel) 35 | } 36 | 37 | override fun newArray(size: Int): Array { 38 | return arrayOfNulls(size) 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/data/repository/HotelRepository.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.data.repository 2 | 3 | import android.location.Address 4 | import androidx.annotation.StringDef 5 | import com.captech.android.demos.slices.R 6 | import com.captech.android.demos.slices.data.model.Hotel 7 | import java.util.* 8 | 9 | class HotelRepository { 10 | 11 | companion object SortBy { 12 | const val NONE = "NONE" 13 | const val PRICE = "PRICE" 14 | const val DISTANCE = "DISTANCE" 15 | } 16 | 17 | @Retention(AnnotationRetention.SOURCE) 18 | @StringDef( 19 | NONE, 20 | PRICE, 21 | DISTANCE 22 | ) 23 | annotation class SortingOptions { 24 | } 25 | 26 | var hotels: List = emptyList() 27 | 28 | constructor() { 29 | var hotel1 = Hotel( 30 | "Hilariott Richmond", 31 | 134.00, 32 | R.drawable.ic_hotel_01, 33 | Address(Locale.getDefault()) 34 | .apply { 35 | setAddressLine(1, "1 2nd St") 36 | latitude = 38.971624 37 | longitude = -76.479221 38 | } 39 | ) 40 | var hotel2 = Hotel( 41 | "Days Weeks Inn RVA", 42 | 189.00, 43 | R.drawable.ic_hotel_02, 44 | Address(Locale.getDefault()) 45 | .apply { 46 | setAddressLine(1, "618 N 1st St") 47 | latitude = 37.548868 48 | longitude = -77.437728 49 | } 50 | ) 51 | var hotel3 = Hotel( 52 | "Ritzni Short Pump", 53 | 140.00, 54 | R.drawable.ic_hotel_03, 55 | Address(Locale.getDefault()) 56 | .apply { 57 | setAddressLine(1, "613 N 2nd St") 58 | latitude = 37.548056 59 | longitude = -77.436695 60 | } 61 | ) 62 | var hotel4 = Hotel( 63 | "La Rancharia RVA", 64 | 99.00, 65 | R.drawable.ic_hotel_04, 66 | Address(Locale.getDefault()) 67 | .apply { 68 | setAddressLine(1, "514 N 3rd St") 69 | latitude = 37.546705 70 | longitude = -77.436780 71 | } 72 | ) 73 | var hotel5 = Hotel( 74 | "Motel Hotel Richmond", 75 | 102.00, 76 | R.drawable.ic_hotel_05, 77 | Address(Locale.getDefault()) 78 | .apply { 79 | setAddressLine(1, "708 E Broad St") 80 | latitude = 37.541859 81 | longitude = -77.435245 82 | } 83 | ) 84 | var hotel6 = Hotel( 85 | "Fancy Place Inn Richmond", 86 | 201.00, 87 | R.drawable.ic_hotel_06, 88 | Address(Locale.getDefault()) 89 | .apply { 90 | setAddressLine(1, "1200 E Cary St") 91 | latitude = 37.535886 92 | longitude = -77.434301 93 | } 94 | ) 95 | var hotel7 = Hotel( 96 | "The Grand Richmond", 97 | 249.00, 98 | R.drawable.ic_hotel_07, 99 | Address(Locale.getDefault()) 100 | .apply { 101 | setAddressLine(1, "100 S 12th St") 102 | latitude = 37.535777 103 | longitude = -77.435494 104 | } 105 | ) 106 | hotels = listOf(hotel1, hotel2, hotel3, hotel4, hotel5, hotel6, hotel7) 107 | } 108 | } -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/provider/BankSliceProvider.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.provider 2 | 3 | import android.app.PendingIntent 4 | import android.content.ContentResolver 5 | import android.content.Intent 6 | import android.graphics.Color 7 | import android.net.Uri 8 | import androidx.core.graphics.drawable.IconCompat 9 | 10 | import androidx.slice.Slice 11 | import androidx.slice.SliceProvider 12 | import androidx.slice.builders.ListBuilder 13 | import androidx.slice.builders.ListBuilder.SMALL_IMAGE 14 | import androidx.slice.builders.SliceAction 15 | import com.captech.android.demos.slices.R 16 | import com.captech.android.demos.slices.SendMoneyActivity 17 | 18 | class BankSliceProvider : SliceProvider() { 19 | /** 20 | * Instantiate any required objects. Return true if the provider was successfully created, 21 | * false otherwise. 22 | */ 23 | override fun onCreateSliceProvider(): Boolean { 24 | return true 25 | } 26 | 27 | /** 28 | * Converts URL to content URI (i.e. content://com.captech.bankingslices...) 29 | */ 30 | override fun onMapIntentToUri(intent: Intent?): Uri { 31 | // Note: implementing this is only required if you plan on catching URL requests. 32 | // This is an example solution. 33 | var uriBuilder: Uri.Builder = Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 34 | if (intent == null) return uriBuilder.build() 35 | val data = intent.data 36 | if (data != null && data.path != null) { 37 | val path = data.path.replace("/", "") 38 | uriBuilder = uriBuilder.path(path) 39 | } 40 | 41 | if (context != null) { 42 | uriBuilder = uriBuilder.authority(context.packageName) 43 | } 44 | return uriBuilder.build() 45 | } 46 | 47 | /** 48 | * Construct the Slice and bind data if available. 49 | */ 50 | override fun onBindSlice(sliceUri: Uri): Slice? { 51 | return when { 52 | sliceUri.path == "/atm" -> createAtmSlice(sliceUri) 53 | sliceUri.path == "/paymentdue" -> createPaymentDueSlice(sliceUri) 54 | else -> null 55 | } 56 | } 57 | 58 | private fun createPaymentDueSlice(sliceUri: Uri): Slice { 59 | return ListBuilder(context, sliceUri, ListBuilder.INFINITY) 60 | .setAccentColor(Color.parseColor("#3cba54")) // Specify color for tinting icons 61 | .addRow { 62 | it.apply { 63 | setTitle("Payment Due: 5/20/18") 64 | setSubtitle("Amount: $234.56") 65 | addEndItem(sendMoneyAction()) 66 | } 67 | } 68 | .build() 69 | } 70 | 71 | private fun createAtmSlice(sliceUri: Uri): Slice { 72 | // Create the parent builder. 73 | return ListBuilder(context, sliceUri, ListBuilder.INFINITY) 74 | .setAccentColor(Color.parseColor("#000000")) 75 | .setHeader { 76 | it.apply { 77 | setTitle("Nearby ATMs") 78 | setSubtitle("Within 5 miles") 79 | setPrimaryAction(mapsAction()) 80 | } 81 | } 82 | .addAction(mapsAction()) 83 | .addGridRow { 84 | it.apply { 85 | addCell { 86 | it.apply { 87 | addImage(IconCompat.createWithResource(context, R.drawable.bank).setTint(Color.parseColor("#db3236")), SMALL_IMAGE) 88 | addTitleText("Bank 1") 89 | addText("0.7 mi") 90 | setContentIntent(mapsIntent()) 91 | } 92 | } 93 | addCell { 94 | it.apply { 95 | addImage(IconCompat.createWithResource(context, R.drawable.bank).setTint(Color.parseColor("#f4c20d")), SMALL_IMAGE) 96 | addTitleText("Bank 2") 97 | addText("2.5 mi") 98 | setContentIntent(mapsIntent()) 99 | } 100 | } 101 | addCell { 102 | it.apply { 103 | addImage(IconCompat.createWithResource(context, R.drawable.bank).setTint(Color.parseColor("#3cba54")), SMALL_IMAGE) 104 | addTitleText("Bank 3") 105 | addText("2.9 mi") 106 | setContentIntent(mapsIntent()) 107 | } 108 | } 109 | addCell { 110 | it.apply { 111 | addImage(IconCompat.createWithResource(context, R.drawable.bank).setTint(Color.parseColor("#4885ed")), SMALL_IMAGE) 112 | addTitleText("Bank 4") 113 | addText("4.2 mi") 114 | setContentIntent(mapsIntent()) 115 | } 116 | } 117 | } 118 | } 119 | .build() 120 | } 121 | 122 | private fun mapsIntent(): PendingIntent { 123 | val gmmIntentUri = Uri.parse("google.navigation:q=7100+Forest+Ave, Richmond+Virginia") 124 | val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) 125 | mapIntent.`package` = "com.google.android.apps.maps" 126 | return PendingIntent.getActivity(context, 0, mapIntent, 0) 127 | } 128 | 129 | private fun mapsAction(): SliceAction { 130 | return SliceAction(mapsIntent(), 131 | IconCompat.createWithResource(context, R.drawable.ic_map_marker), 132 | "Open Google Maps." 133 | ) 134 | } 135 | 136 | private fun sendMoneyAction(): SliceAction { 137 | val sendMoneyIntent = Intent(context, SendMoneyActivity::class.java) 138 | return SliceAction(PendingIntent.getActivity(context, 0, sendMoneyIntent, 0), 139 | IconCompat.createWithResource(context, R.drawable.ic_send_money), "Send Money Action") 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/provider/ContentUris.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.provider 2 | 3 | import android.net.Uri 4 | 5 | class ContentUris { 6 | 7 | companion object { 8 | val URI_MAKE = Uri.parse(ReservationUriStrings.RESERVATION_MAKE) 9 | val URI_READY = Uri.parse(ReservationUriStrings.RESERVATION_READY) 10 | val URI_RATE = Uri.parse(ReservationUriStrings.RESERVATION_RATE) 11 | } 12 | 13 | class ReservationUriStrings { 14 | companion object { 15 | const val RESERVATION_MAKE = "content://com.captech.android.demos.slices.provider" + ReservationPaths.MAKE 16 | const val RESERVATION_READY = "content://com.captech.android.demos.slices.provider" + ReservationPaths.READY 17 | const val RESERVATION_RATE = "content://com.captech.android.demos.slices.provider" + ReservationPaths.RATE 18 | } 19 | } 20 | 21 | class ReservationPaths { 22 | companion object { 23 | const val MAKE = "/make-reservation" 24 | const val READY = "/reservation" 25 | const val RATE = "/rate-reservation" 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/provider/HotelSliceProvider.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.provider 2 | 3 | import android.app.PendingIntent 4 | import android.content.ContentResolver 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.net.Uri 8 | import androidx.core.graphics.drawable.IconCompat 9 | import androidx.slice.Slice 10 | import androidx.slice.SliceProvider 11 | import androidx.slice.builders.GridRowBuilder 12 | import androidx.slice.builders.ListBuilder 13 | import androidx.slice.builders.ListBuilder.* 14 | import androidx.slice.builders.SliceAction 15 | import com.captech.android.demos.slices.* 16 | import com.captech.android.demos.slices.data.model.Hotel 17 | import com.captech.android.demos.slices.data.repository.HotelRepository 18 | import com.captech.android.demos.slices.receiver.HotelsBroadcastReceiver 19 | import com.captech.android.demos.slices.util.HotelUtils 20 | import java.text.DecimalFormat 21 | import java.text.NumberFormat 22 | import java.util.* 23 | 24 | class HotelSliceProvider : SliceProvider() { 25 | 26 | /** 27 | * Instantiate any required objects. Return true if the provider was successfully created, 28 | * false otherwise. 29 | */ 30 | override fun onCreateSliceProvider(): Boolean { 31 | return true 32 | } 33 | 34 | /** 35 | * Converts URL to content URI (i.e. content://com.captech.android.demos.slices.provider...) 36 | */ 37 | override fun onMapIntentToUri(intent: Intent?): Uri { 38 | // Note: implementing this is only required if you plan on catching URL requests. 39 | // This is an example solution. 40 | var uriBuilder: Uri.Builder = Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 41 | if (intent == null) return uriBuilder.build() 42 | val data = intent.data 43 | if (data != null && data.path != null) { 44 | val path = data.path.replace("/", "") 45 | uriBuilder = uriBuilder.path(path) 46 | } 47 | val context = context 48 | if (context != null) { 49 | uriBuilder = uriBuilder.authority(context.getPackageName()) 50 | } 51 | return uriBuilder.build() 52 | } 53 | 54 | /** 55 | * Construct the Slice and bind data if available. 56 | */ 57 | override fun onBindSlice(sliceUri: Uri): Slice? { 58 | val context = getContext() ?: return null 59 | return when { 60 | sliceUri.path.equals(ContentUris.ReservationPaths.MAKE, true) -> 61 | createSliceMakeReservation(context, sliceUri) 62 | sliceUri.path.equals(ContentUris.ReservationPaths.READY, true) -> 63 | createSliceReservationReady(context, sliceUri) 64 | sliceUri.path.equals(ContentUris.ReservationPaths.RATE, true) -> 65 | createSliceRateReservation(context, sliceUri) 66 | else -> null 67 | } 68 | } 69 | 70 | private fun createSliceMakeReservation(context: Context, sliceUri: Uri): Slice? { 71 | val maxHotels = 3; 72 | val hotelRepo = HotelRepository(); 73 | val hotels: List = getSortedHotels(context, hotelRepo).take(maxHotels) 74 | val seeMoreAction = SliceAction(createSeeMoreIntent(), 75 | IconCompat.createWithResource(context, R.drawable.ic_more), 76 | ICON_IMAGE, "Sort by Price") 77 | val sortByPriceAction = SliceAction(createSortByPriceIntent(), 78 | IconCompat.createWithResource(context, R.drawable.ic_sort_price), 79 | ICON_IMAGE, "Sort by Price") 80 | val sortByDistanceAction = SliceAction(createSortByDistanceIntent(), 81 | IconCompat.createWithResource(context, R.drawable.ic_map_marker_distance), 82 | ICON_IMAGE, "Sort by Distance") 83 | val listBuilder = ListBuilder(context, sliceUri, ListBuilder.INFINITY) 84 | .setHeader { 85 | it.apply { 86 | setTitle("Make a Reservation") 87 | setPrimaryAction(seeMoreAction) 88 | } 89 | } 90 | .addAction(seeMoreAction) 91 | val gridRowBuilder = GridRowBuilder(listBuilder) 92 | 93 | hotels.forEach { hotel -> 94 | gridRowBuilder.addCell { 95 | it.apply { 96 | addImage(IconCompat.createWithResource(context, hotel.imageResId), LARGE_IMAGE) 97 | addTitleText(hotel.name) 98 | addText(getPriceAndDistance(context, hotel)) 99 | setContentIntent(createViewHotelIntent(hotel)) 100 | } 101 | } 102 | } 103 | listBuilder.addGridRow(gridRowBuilder) 104 | listBuilder.addRow() { 105 | it.apply { 106 | setTitle("Sort Hotels") 107 | setSubtitle(getSubtitleMakeReservation()) 108 | addEndItem(sortByPriceAction) 109 | addEndItem(sortByDistanceAction) 110 | } 111 | } 112 | return listBuilder.build() 113 | } 114 | 115 | private fun createSliceReservationReady(context: Context, sliceUri: Uri): Slice? { 116 | val hotelRepo = HotelRepository(); 117 | val hotel = hotelRepo.hotels.first(); 118 | val checkInAction = SliceAction(createCheckInIntent(), 119 | IconCompat.createWithResource(context, R.drawable.ic_marker_check), 120 | ICON_IMAGE, "Check In") 121 | val messageHotelAction = SliceAction(createMessageIntent(), 122 | IconCompat.createWithResource(context, R.drawable.ic_forum), 123 | ICON_IMAGE, "Message the Front Desk") 124 | val listBuilder = ListBuilder(context, sliceUri, ListBuilder.INFINITY) 125 | .setHeader { 126 | it.apply { 127 | setTitle("Your Reservation is Ready") 128 | setPrimaryAction(checkInAction) 129 | } 130 | } 131 | .addAction(checkInAction) 132 | .addAction(messageHotelAction) 133 | .addGridRow { 134 | it.apply { 135 | addCell { 136 | it.apply { 137 | addImage(IconCompat.createWithResource(context, hotel.imageResId), LARGE_IMAGE) 138 | addTitleText(hotel.name) 139 | addText(getPriceAndDistance(context, hotel)) 140 | setContentIntent(createViewHotelIntent(hotel)) 141 | } 142 | } 143 | } 144 | } 145 | return listBuilder.build() 146 | } 147 | 148 | private fun createSliceRateReservation(context: Context, sliceUri: Uri): Slice? { 149 | val listBuilder = ListBuilder(context, sliceUri, ListBuilder.INFINITY) 150 | .setHeader { 151 | it.apply { 152 | setTitle("Rate Your Stay") 153 | } 154 | } 155 | val gridRowBuilder = GridRowBuilder(listBuilder) 156 | 157 | val rating = (context.applicationContext as SlicesApplication).appState.rating 158 | val remainingRating = HotelUtils.getRemainingRating(rating); 159 | for (i in 1..rating) { 160 | gridRowBuilder.addCell { 161 | it.apply { 162 | addImage(IconCompat.createWithResource(context, R.drawable.ic_star_filled), SMALL_IMAGE) 163 | setContentIntent(createSetRatingIntent(i)) 164 | } 165 | } 166 | } 167 | if (rating < HotelUtils.MAX_RATING) { 168 | for (i in rating + 1..(rating + remainingRating)) { 169 | gridRowBuilder.addCell { 170 | it.apply { 171 | addImage(IconCompat.createWithResource(context, R.drawable.ic_star), SMALL_IMAGE) 172 | setContentIntent(createSetRatingIntent(i)) 173 | } 174 | } 175 | } 176 | } 177 | listBuilder.addGridRow(gridRowBuilder) 178 | return listBuilder.build() 179 | } 180 | 181 | private fun getSubtitleMakeReservation(): CharSequence { 182 | @HotelRepository.SortingOptions val sortBy = (context.applicationContext as SlicesApplication).appState.sortingType 183 | return if (!HotelRepository.NONE.equals(sortBy, true)) "By " + sortBy else ""; 184 | } 185 | 186 | private fun getSortedHotels(context: Context, hotelRepo: HotelRepository): List { 187 | @HotelRepository.SortingOptions val sortBy = (context.applicationContext as SlicesApplication).appState.sortingType 188 | return when { 189 | HotelRepository.PRICE.equals(sortBy, true) -> 190 | hotelRepo.hotels.sortedWith(compareBy({ it.ratePerNight })) 191 | HotelRepository.DISTANCE.equals(sortBy, true) -> 192 | hotelRepo.hotels.sortedWith(compareBy({ HotelUtils.getDistanceInMiles(context, it.address) })) 193 | else -> 194 | hotelRepo.hotels 195 | } 196 | } 197 | 198 | private fun getPriceAndDistance(context: Context, hotel: Hotel): String { 199 | val currencyInstance = NumberFormat.getCurrencyInstance(Locale.getDefault()) 200 | val formatter = DecimalFormat("#0.00") 201 | val price = currencyInstance.format(hotel.ratePerNight) 202 | val distance = formatter.format(HotelUtils.getDistanceInMiles(context, hotel.address)) 203 | return price + " - " + distance + "mi" 204 | } 205 | 206 | private fun createSortByPriceIntent(): PendingIntent { 207 | val intent = Intent(context, HotelsBroadcastReceiver::class.java) 208 | val requestCode = HotelsBroadcastReceiver.REQUEST_CODE_SORT_BY_PRICE 209 | intent.putExtra(HotelsBroadcastReceiver.EXTRA_REQUEST_CODE, requestCode) 210 | return PendingIntent.getBroadcast(context, requestCode, intent, 0) 211 | } 212 | 213 | private fun createSortByDistanceIntent(): PendingIntent { 214 | val intent = Intent(context, HotelsBroadcastReceiver::class.java) 215 | val requestCode = HotelsBroadcastReceiver.REQUEST_CODE_SORT_BY_DISTANCE 216 | intent.putExtra(HotelsBroadcastReceiver.EXTRA_REQUEST_CODE, requestCode) 217 | return PendingIntent.getBroadcast(context, requestCode, intent, 0) 218 | } 219 | 220 | private fun createSeeMoreIntent(): PendingIntent { 221 | val intent = Intent(context, SeeMoreHotelsActivity::class.java) 222 | val requestCode = SeeMoreHotelsActivity.REQUEST_CODE_SEE_MORE_HOTELS 223 | intent.setAction(System.currentTimeMillis().toString()) 224 | return PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT) 225 | } 226 | 227 | private fun createViewHotelIntent(hotel: Hotel): PendingIntent { 228 | val intent = Intent(context, ViewHotelActivity::class.java) 229 | val requestCode = ViewHotelActivity.REQUEST_CODE_VIEW_HOTEL 230 | intent.putExtra(ViewHotelActivity.EXTRA_HOTEL, hotel) 231 | intent.setAction(System.currentTimeMillis().toString()) 232 | return PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT) 233 | } 234 | 235 | private fun createCheckInIntent(): PendingIntent { 236 | val intent = Intent(context, HotelsBroadcastReceiver::class.java) 237 | val requestCode = HotelsBroadcastReceiver.REQUEST_CODE_CHECK_IN 238 | intent.putExtra(HotelsBroadcastReceiver.EXTRA_REQUEST_CODE, requestCode) 239 | return PendingIntent.getBroadcast(context, requestCode, intent, 0) 240 | } 241 | 242 | private fun createMessageIntent(): PendingIntent { 243 | val intent = Intent(context, MessageHotelActivity::class.java) 244 | val requestCode = MessageHotelActivity.REQUEST_CODE_MESSAGE_HOTEL 245 | intent.setAction(System.currentTimeMillis().toString()) 246 | return PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT) 247 | } 248 | 249 | private fun createSetRatingIntent(rating: Int): PendingIntent { 250 | val intent = Intent(context, HotelsBroadcastReceiver::class.java) 251 | val requestCode = HotelsBroadcastReceiver.REQUEST_CODE_SET_RATING 252 | intent.putExtra(HotelsBroadcastReceiver.EXTRA_REQUEST_CODE, requestCode) 253 | intent.putExtra(HotelsBroadcastReceiver.EXTRA_RATING, rating) 254 | intent.setAction(System.currentTimeMillis().toString()) 255 | return PendingIntent.getBroadcast(context, requestCode, intent, 0) 256 | } 257 | 258 | /** 259 | * Slice has been pinned to external process. Subscribe to data source if necessary. 260 | */ 261 | override fun onSlicePinned(sliceUri: Uri?) { 262 | // When data is received, call context.contentResolver.notifyChange(sliceUri, null) to 263 | // trigger HotelSliceProvider#onBindSlice(Uri) again. 264 | } 265 | 266 | /** 267 | * Unsubscribe from data source if necessary. 268 | */ 269 | override fun onSliceUnpinned(sliceUri: Uri?) { 270 | // Remove any observers if necessary to avoid memory leaks. 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/receiver/HotelsBroadcastReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.receiver 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.widget.Toast 7 | import com.captech.android.demos.slices.SlicesApplication 8 | import com.captech.android.demos.slices.data.repository.HotelRepository 9 | import com.captech.android.demos.slices.provider.ContentUris 10 | 11 | class HotelsBroadcastReceiver : BroadcastReceiver() { 12 | 13 | companion object { 14 | const val REQUEST_CODE_SORT_BY_PRICE = 2001 15 | const val REQUEST_CODE_SORT_BY_DISTANCE = 2002 16 | const val REQUEST_CODE_CHECK_IN = 2003 17 | const val REQUEST_CODE_SET_RATING = 2004 18 | const val EXTRA_REQUEST_CODE = "EXTRA_REQUEST_CODE" 19 | const val EXTRA_RATING = "EXTRA_RATING" 20 | } 21 | 22 | override fun onReceive(context: Context?, intent: Intent?) { 23 | if (intent != null && intent.hasExtra(EXTRA_REQUEST_CODE)) { 24 | val requestCode = intent.getIntExtra(EXTRA_REQUEST_CODE, REQUEST_CODE_SORT_BY_PRICE) 25 | when { 26 | requestCode == REQUEST_CODE_SORT_BY_PRICE -> { 27 | setSortingType(context, HotelRepository.SortBy.PRICE) 28 | refreshReservationList(context) 29 | } 30 | requestCode == REQUEST_CODE_SORT_BY_DISTANCE -> { 31 | setSortingType(context, HotelRepository.SortBy.DISTANCE) 32 | refreshReservationList(context) 33 | } 34 | requestCode == REQUEST_CODE_CHECK_IN -> { 35 | Toast.makeText(context, "Checking you in - Enjoy your stay!", 36 | Toast.LENGTH_LONG).show() 37 | } 38 | requestCode == REQUEST_CODE_SET_RATING -> { 39 | if (intent.hasExtra(EXTRA_RATING)) { 40 | val rating = intent.getIntExtra(EXTRA_RATING, 0) 41 | Toast.makeText(context, "Rate Clicked " + rating, 42 | Toast.LENGTH_LONG).show() 43 | setRating(context, rating) 44 | refreshRating(context) 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | private fun refreshReservationList(context: Context?) { 52 | if (context != null) { 53 | context.contentResolver.notifyChange(ContentUris.URI_MAKE, null) 54 | } 55 | } 56 | 57 | private fun refreshRating(context: Context?) { 58 | if (context != null) { 59 | context.contentResolver.notifyChange(ContentUris.URI_RATE, null) 60 | } 61 | } 62 | 63 | private fun setSortingType(context: Context?, @HotelRepository.SortingOptions sortingOption: String) { 64 | val application = getApplication(context) 65 | if (application != null) { 66 | application.appState.sortingType = sortingOption 67 | } 68 | } 69 | 70 | private fun setRating(context: Context?, rating: Int) { 71 | val application = getApplication(context) 72 | if (application != null) { 73 | application.appState.rating = rating 74 | } 75 | } 76 | 77 | private fun getApplication(context: Context?): SlicesApplication? { 78 | return if (context != null) 79 | context.applicationContext as SlicesApplication 80 | else null 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/state/AppState.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.state 2 | 3 | import com.captech.android.demos.slices.data.repository.HotelRepository 4 | 5 | class AppState() { 6 | @HotelRepository.SortingOptions 7 | var sortingType = HotelRepository.SortBy.NONE 8 | var rating = 0; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/main/MainFragment.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.main 2 | 3 | import androidx.lifecycle.ViewModelProviders 4 | import android.os.Bundle 5 | import androidx.fragment.app.Fragment 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import com.captech.android.demos.slices.R 10 | 11 | class MainFragment : Fragment() { 12 | 13 | companion object { 14 | fun newInstance() = MainFragment() 15 | } 16 | 17 | private lateinit var viewModel: MainViewModel 18 | 19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 20 | savedInstanceState: Bundle?): View { 21 | return inflater.inflate(R.layout.fragment_main, container, false) 22 | } 23 | 24 | override fun onActivityCreated(savedInstanceState: Bundle?) { 25 | super.onActivityCreated(savedInstanceState) 26 | viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) 27 | // TODO: Use the ViewModel 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/main/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.main 2 | 3 | import androidx.lifecycle.ViewModel 4 | 5 | class MainViewModel : ViewModel() { 6 | // TODO: Implement the ViewModel 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/messagehotel/MessageHotelFragment.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.messagehotel 2 | 3 | import androidx.lifecycle.ViewModelProviders 4 | import android.os.Bundle 5 | import androidx.fragment.app.Fragment 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import com.captech.android.demos.slices.R 10 | 11 | class MessageHotelFragment : Fragment() { 12 | 13 | companion object { 14 | fun newInstance() = MessageHotelFragment() 15 | } 16 | 17 | private lateinit var viewModel: MessageHotelViewModel 18 | 19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 20 | savedInstanceState: Bundle?): View { 21 | return inflater.inflate(R.layout.fragment_message_hotel, container, false) 22 | } 23 | 24 | override fun onActivityCreated(savedInstanceState: Bundle?) { 25 | super.onActivityCreated(savedInstanceState) 26 | viewModel = ViewModelProviders.of(this).get(MessageHotelViewModel::class.java) 27 | // TODO: Use the ViewModel 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/messagehotel/MessageHotelViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.messagehotel 2 | 3 | import androidx.lifecycle.ViewModel 4 | 5 | class MessageHotelViewModel : ViewModel() { 6 | // TODO: Implement the ViewModel 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/seemorehotels/SeeMoreHotelsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.seemorehotels 2 | 3 | import androidx.lifecycle.ViewModelProviders 4 | import android.os.Bundle 5 | import androidx.fragment.app.Fragment 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import com.captech.android.demos.slices.R 10 | 11 | class SeeMoreHotelsFragment : Fragment() { 12 | 13 | companion object { 14 | fun newInstance() = SeeMoreHotelsFragment() 15 | } 16 | 17 | private lateinit var viewModel: SeeMoreHotelsViewModel 18 | 19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 20 | savedInstanceState: Bundle?): View { 21 | return inflater.inflate(R.layout.fragment_see_more_hotels, container, false) 22 | } 23 | 24 | override fun onActivityCreated(savedInstanceState: Bundle?) { 25 | super.onActivityCreated(savedInstanceState) 26 | viewModel = ViewModelProviders.of(this).get(SeeMoreHotelsViewModel::class.java) 27 | // TODO: Use the ViewModel 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/seemorehotels/SeeMoreHotelsViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.seemorehotels 2 | 3 | import androidx.lifecycle.ViewModel 4 | 5 | class SeeMoreHotelsViewModel : ViewModel() { 6 | // TODO: Implement the ViewModel 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/viewhotel/ViewHotelFragment.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.viewhotel 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.ImageView 8 | import android.widget.TextView 9 | import androidx.core.content.ContextCompat 10 | import androidx.fragment.app.Fragment 11 | import androidx.lifecycle.ViewModelProviders 12 | import com.captech.android.demos.slices.R 13 | import com.captech.android.demos.slices.data.model.Hotel 14 | 15 | class ViewHotelFragment : Fragment() { 16 | 17 | companion object { 18 | const val EXTRA_HOTEL: String = "EXTRA_HOTEL" 19 | fun newInstance(hotel: Hotel?): ViewHotelFragment { 20 | val viewHotelFragment = ViewHotelFragment() 21 | val args = Bundle() 22 | if (hotel != null) { 23 | args.putParcelable(EXTRA_HOTEL, hotel) 24 | } 25 | viewHotelFragment.arguments = args 26 | return viewHotelFragment 27 | } 28 | } 29 | 30 | private lateinit var viewModel: ViewHotelViewModel 31 | 32 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 33 | savedInstanceState: Bundle?): View { 34 | viewModel = ViewModelProviders.of(this).get(ViewHotelViewModel::class.java) 35 | if (arguments != null && arguments!!.containsKey(EXTRA_HOTEL)) { 36 | viewModel.hotel = arguments!!.getParcelable(EXTRA_HOTEL) 37 | } 38 | val view = inflater.inflate(R.layout.fragment_view_hotel, container, false) 39 | view.findViewById(R.id.hotel_name).setText(viewModel.hotel.name) 40 | view.findViewById(R.id.image_hotel_image).setImageDrawable(ContextCompat.getDrawable(activity!!.applicationContext, viewModel.hotel.imageResId)) 41 | return view 42 | } 43 | 44 | override fun onActivityCreated(savedInstanceState: Bundle?) { 45 | super.onActivityCreated(savedInstanceState) 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/ui/viewhotel/ViewHotelViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.ui.viewhotel 2 | 3 | import android.os.Parcel 4 | import android.os.Parcelable 5 | import androidx.databinding.Bindable 6 | import androidx.lifecycle.ViewModel 7 | import com.captech.android.demos.slices.data.model.Hotel 8 | 9 | class ViewHotelViewModel() : ViewModel(), Parcelable { 10 | 11 | @Bindable 12 | lateinit var hotel: Hotel 13 | 14 | constructor(parcel: Parcel) : this() { 15 | hotel = parcel.readParcelable(Hotel::class.java.classLoader) 16 | } 17 | 18 | override fun writeToParcel(parcel: Parcel, flags: Int) { 19 | parcel.writeParcelable(hotel, flags) 20 | } 21 | 22 | override fun describeContents(): Int { 23 | return 0 24 | } 25 | 26 | companion object CREATOR : Parcelable.Creator { 27 | override fun createFromParcel(parcel: Parcel): ViewHotelViewModel { 28 | return ViewHotelViewModel(parcel) 29 | } 30 | 31 | override fun newArray(size: Int): Array { 32 | return arrayOfNulls(size) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/captech/android/demos/slices/util/HotelUtils.kt: -------------------------------------------------------------------------------- 1 | package com.captech.android.demos.slices.util 2 | 3 | import android.content.Context 4 | import android.location.Address 5 | import java.util.* 6 | 7 | class HotelUtils { 8 | companion object { 9 | const val MAX_RATING: Int = 5; 10 | fun getDistanceInMiles(context: Context, address: Address): Double { 11 | return 0.2 + Random(address.hashCode().toLong()).nextDouble(); 12 | } 13 | 14 | fun getRemainingRating(rating: Int): Int { 15 | return MAX_RATING - rating; 16 | } 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hotel_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-hdpi/ic_hotel_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hotel_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-hdpi/ic_hotel_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hotel_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-hdpi/ic_hotel_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hotel_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-hdpi/ic_hotel_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hotel_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-hdpi/ic_hotel_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hotel_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-hdpi/ic_hotel_06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_hotel_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-hdpi/ic_hotel_07.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hotel_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-mdpi/ic_hotel_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hotel_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-mdpi/ic_hotel_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hotel_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-mdpi/ic_hotel_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hotel_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-mdpi/ic_hotel_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hotel_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-mdpi/ic_hotel_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hotel_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-mdpi/ic_hotel_06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_hotel_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-mdpi/ic_hotel_07.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 15 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hotel_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xhdpi/ic_hotel_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hotel_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xhdpi/ic_hotel_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hotel_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xhdpi/ic_hotel_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hotel_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xhdpi/ic_hotel_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hotel_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xhdpi/ic_hotel_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hotel_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xhdpi/ic_hotel_06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_hotel_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xhdpi/ic_hotel_07.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hotel_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxhdpi/ic_hotel_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hotel_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxhdpi/ic_hotel_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hotel_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxhdpi/ic_hotel_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hotel_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxhdpi/ic_hotel_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hotel_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxhdpi/ic_hotel_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hotel_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxhdpi/ic_hotel_06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hotel_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxhdpi/ic_hotel_07.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_hotel_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxxhdpi/ic_hotel_01.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_hotel_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxxhdpi/ic_hotel_02.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_hotel_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxxhdpi/ic_hotel_03.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_hotel_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxxhdpi/ic_hotel_04.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_hotel_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxxhdpi/ic_hotel_05.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_hotel_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxxhdpi/ic_hotel_06.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_hotel_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/drawable-xxxhdpi/ic_hotel_07.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bank.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_directions.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_forum.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_map_marker.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_map_marker_distance.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_marker_check.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_send_money.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 12 | 16 | 17 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort_ascending.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort_descending.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort_price.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 13 | 17 | 18 | 20 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star_filled.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/ic_hotel_01.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapTechMobile/Android-Slices/ac79411a12d453c654a9bd4e617b2a272fc1b0a1/app/src/main/res/ic_hotel_01.zip -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_message_hotel.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_see_more_hotels.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_send_money.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |