Merge pull request #4367 from goblinr/MAPSME-1-external-place-page-booking

[android] place page booking
This commit is contained in:
burivuh 2016-10-05 20:22:18 +03:00 committed by GitHub
commit d487f11baa
106 changed files with 4074 additions and 360 deletions

View file

@ -71,11 +71,11 @@
<meta-data
android:name="PW_APPID"
android:value="${PW_APPID}" />
android:value="${PW_APPID}"/>
<meta-data
android:name="PW_PROJECT_ID"
android:value="${PW_PROJECT_ID}" />
android:value="${PW_PROJECT_ID}"/>
<!--meta-data
android:name="PW_LOG_LEVEL"
@ -241,52 +241,79 @@
</activity>
<activity
android:name="com.mapswithme.maps.editor.EditorActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/edit_place"
android:theme="@style/MwmTheme.EditorActivity"
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
android:name="com.mapswithme.maps.editor.EditorActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/edit_place"
android:theme="@style/MwmTheme.EditorActivity"
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.ProfileActivity"
android:parentActivityName="com.mapswithme.maps.settings.SettingsActivity">
android:name="com.mapswithme.maps.editor.ProfileActivity"
android:parentActivityName="com.mapswithme.maps.settings.SettingsActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.settings.SettingsActivity"/>
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.settings.SettingsActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.FeatureCategoryActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
android:name="com.mapswithme.maps.editor.FeatureCategoryActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.ReportActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
android:name="com.mapswithme.maps.editor.ReportActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.editor.OsmAuthActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
android:name="com.mapswithme.maps.editor.OsmAuthActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.gallery.GalleryActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.gallery.FullScreenGalleryActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<activity
android:name="com.mapswithme.maps.review.ReviewActivity"
android:parentActivityName="com.mapswithme.maps.MwmActivity">
<!-- The meta-data element is needed for versions lower than 4.1 -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapswithme.maps.MwmActivity"/>
</activity>
<!-- facebook -->
@ -346,17 +373,17 @@
</receiver>
<!-- PushWoosh -->
<activity android:name="com.pushwoosh.richpages.RichPageActivity" />
<activity android:name="com.pushwoosh.MessageActivity" />
<activity android:name="com.pushwoosh.PushHandlerActivity" />
<activity android:name="com.pushwoosh.richpages.RichPageActivity"/>
<activity android:name="com.pushwoosh.MessageActivity"/>
<activity android:name="com.pushwoosh.PushHandlerActivity"/>
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<category android:name="${applicationId}"/>
</intent-filter>
</receiver>
@ -378,10 +405,10 @@
<service
android:name="com.pushwoosh.GCMRegistrationService"
android:exported="false" />
android:exported="false"/>
<service
android:name="com.pushwoosh.location.GeoLocationService" />
android:name="com.pushwoosh.location.GeoLocationService"/>
<!-- Catches app upgraded intent -->
<receiver android:name=".background.UpgradeReceiver">

View file

@ -57,6 +57,8 @@ dependencies {
// TODO remove this library when default LinearLayoutManager will be fixed.
compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar'
compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'
//Glide
compile 'com.github.bumptech.glide:glide:3.7.0'
}
def getDate() {
@ -93,15 +95,15 @@ android {
// Crashlytics API key
Properties props = new Properties()
props.load(new FileInputStream("${projectDir}/fabric.properties"));
manifestPlaceholders = [ 'FABRIC_API_KEY': props['apiKey'] ]
manifestPlaceholders = ['FABRIC_API_KEY': props['apiKey']]
buildConfigField 'String', 'FABRIC_API_KEY', /"${props['apiKey']}"/
// PushWoosh keys
Properties pwProps = new Properties()
pwProps.load(new FileInputStream("${projectDir}/pushwoosh.properties"));
manifestPlaceholders += [ 'PW_APPID': pwProps['pwAppId'] ]
manifestPlaceholders += ['PW_APPID': pwProps['pwAppId']]
buildConfigField 'String', 'PW_APPID', /"${pwProps['pwAppId']}"/
manifestPlaceholders += [ 'PW_PROJECT_ID': pwProps['pwProjectId'] ]
manifestPlaceholders += ['PW_PROJECT_ID': pwProps['pwProjectId']]
}
sourceSets.main {
@ -210,13 +212,6 @@ android {
android.sourceSets.blackberry.assets.srcDirs = ['flavors/mwm-ttf-assets']
buildConfigField 'String', 'REVIEW_URL', '"https://appworld.blackberry.com/webstore/content/51013892"'
}
nineStore {
versionName = android.defaultConfig.versionName + '-NineStore'
android.sourceSets.blackberry.assets.srcDirs = ['flavors/mwm-ttf-assets']
buildConfigField 'String', 'SUPPORT_MAIL', '"ninestore@mapswithme.com"'
buildConfigField 'String', 'REVIEW_URL', '"http://www.ninestore.ru/android-apps/mapswithme-maps-pro"'
}
}
// Currently (as of 1.2.3 gradle plugin) ABI filters aren't supported inside of product flavors, so we cannot generate splitted builds only for Google build.
@ -331,7 +326,7 @@ if (System.properties['os.name'].toLowerCase().contains('windows'))
project.ext.NDK_BUILD += ".cmd"
def archs = ['x86', 'armeabi-v7a-hard']
def buildTypes = [[ndkType: 'release', cppType: "production", flags : propReleaseNdkFlags], [ndkType: 'debug', cppType: "debug", flags : propDebugNdkFlags]]
def buildTypes = [[ndkType: 'release', cppType: "production", flags: propReleaseNdkFlags], [ndkType: 'debug', cppType: "debug", flags: propDebugNdkFlags]]
buildTypes.each { type ->
def suffix = type.ndkType.capitalize()
@ -408,14 +403,14 @@ obbGenerate.dependsOn obbClean, obbMainGenerate, obbPatchGenerate, obbMainAlign,
def createObbGenerateTask(type, data, name) {
return tasks.create(name: "obb${type}Generate", type: Exec, description: 'Generate obb files') {
commandLine ((['zip', '-0', '-j', name, data]).flatten())
commandLine((['zip', '-0', '-j', name, data]).flatten())
}
}
def createObbAlignTask(type, rawObb, alignedObb) {
def sdkDir = "${android.getSdkDirectory().getAbsolutePath()}"
def zipalignPath = sdkDir + File.separator + "build-tools" + File.separator +
propBuildToolsVersion + File.separator + "zipalign";
propBuildToolsVersion + File.separator + "zipalign";
return tasks.create(name: "obb${type}Align", dependsOn: "obb${type}Generate", type: Exec, description: 'Align obb files') {
commandLine zipalignPath, '-v', '8', rawObb, alignedObb

View file

@ -476,6 +476,12 @@ void Framework::RequestBookingMinPrice(string const & hotelId, string const & cu
return m_work.GetBookingApi().GetMinPrice(hotelId, currencyCode, callback);
}
void Framework::RequestBookingInfo(string const & hotelId, string const & lang,
function<void(BookingApi::HotelInfo const &)> const & callback)
{
return m_work.GetBookingApi().GetHotelInfo(hotelId, lang, callback);
}
bool Framework::HasSpaceForMigration()
{
return m_work.IsEnoughSpaceForMigrate();

View file

@ -155,6 +155,8 @@ namespace android
void SetPlacePageInfo(place_page::Info const & info);
place_page::Info & GetPlacePageInfo();
void RequestBookingMinPrice(string const & hotelId, string const & currency, function<void(string const &, string const &)> const & callback);
void RequestBookingInfo(string const & hotelId, string const & lang,
function<void(BookingApi::HotelInfo const &)> const & callback);
bool HasSpaceForMigration();
storage::TCountryId PreMigrate(ms::LatLon const & position, storage::Storage::TChangeCountryFunction const & statusChangeListener,

View file

@ -2,16 +2,28 @@
#include "../core/jni_helper.hpp"
#include "../platform/Platform.hpp"
#include "map/booking_api.hpp"
#include "map/place_page_info.hpp"
#include "std/bind.hpp"
#include "std/chrono.hpp"
namespace
{
jclass g_hotelClass;
jmethodID g_hotelClassCtor;
jclass g_facilityTypeClass;
jclass g_nearbyObjectClass;
jclass g_imageClass;
jclass g_reviewClass;
jclass g_hotelInfoClass;
jmethodID g_facilityConstructor;
jmethodID g_nearbyConstructor;
jmethodID g_imageConstructor;
jmethodID g_reviewConstructor;
jmethodID g_hotelInfoConstructor;
jmethodID g_hotelClassConstructor;
jmethodID g_priceCallback;
jmethodID g_infoCallback;
void PrepareClassRefs(JNIEnv * env, jclass hotelClass)
{
@ -19,21 +31,51 @@ void PrepareClassRefs(JNIEnv * env, jclass hotelClass)
return;
g_hotelClass = static_cast<jclass>(env->NewGlobalRef(hotelClass));
g_hotelInfoClass =
jni::GetGlobalClassRef(env, "com/mapswithme/maps/widget/placepage/SponsoredHotel$HotelInfo");
g_facilityTypeClass = jni::GetGlobalClassRef(
env, "com/mapswithme/maps/widget/placepage/SponsoredHotel$FacilityType");
g_nearbyObjectClass = jni::GetGlobalClassRef(
env, "com/mapswithme/maps/widget/placepage/SponsoredHotel$NearbyObject");
g_reviewClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/review/Review");
g_imageClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/gallery/Image");
g_facilityConstructor =
jni::GetConstructorID(env, g_facilityTypeClass, "(Ljava/lang/String;Ljava/lang/String;)V");
g_nearbyConstructor = jni::GetConstructorID(
env, g_nearbyObjectClass, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DD)V");
g_imageConstructor =
jni::GetConstructorID(env, g_imageClass, "(Ljava/lang/String;Ljava/lang/String;)V");
g_reviewConstructor = jni::GetConstructorID(env, g_reviewClass,
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/lang/String;Ljava/lang/String;FJ)V");
g_hotelInfoConstructor = jni::GetConstructorID(
env, g_hotelInfoClass,
"(Ljava/lang/String;[Lcom/mapswithme/maps/gallery/Image;[Lcom/mapswithme/maps/widget/"
"placepage/SponsoredHotel$FacilityType;[Lcom/mapswithme/maps/review/Review;[Lcom/mapswithme/"
"maps/widget/placepage/SponsoredHotel$NearbyObject;)V");
// SponsoredHotel(String rating, String price, String urlBook, String urlDescription)
g_hotelClassCtor = jni::GetConstructorID(env, g_hotelClass, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
g_hotelClassConstructor = jni::GetConstructorID(
env, g_hotelClass,
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
// static void onPriceReceived(final String id, final String price, final String currency)
g_priceCallback = jni::GetStaticMethodID(env, g_hotelClass, "onPriceReceived", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
g_priceCallback =
jni::GetStaticMethodID(env, g_hotelClass, "onPriceReceived",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
// static void onDescriptionReceived(final String id, final String description)
g_infoCallback = jni::GetStaticMethodID(
env, g_hotelClass, "onInfoReceived",
"(Ljava/lang/String;Lcom/mapswithme/maps/widget/placepage/SponsoredHotel$HotelInfo;)V");
}
} // namespace
} // namespace
extern "C"
{
extern "C" {
// static SponsoredHotel nativeGetCurrent();
JNIEXPORT jobject JNICALL
Java_com_mapswithme_maps_widget_placepage_SponsoredHotel_nativeGetCurrent(JNIEnv * env, jclass clazz)
JNIEXPORT jobject JNICALL Java_com_mapswithme_maps_widget_placepage_SponsoredHotel_nativeGetCurrent(
JNIEnv * env, jclass clazz)
{
PrepareClassRefs(env, clazz);
@ -41,31 +83,79 @@ Java_com_mapswithme_maps_widget_placepage_SponsoredHotel_nativeGetCurrent(JNIEnv
if (!ppInfo.m_isSponsoredHotel)
return nullptr;
return env->NewObject(g_hotelClass, g_hotelClassCtor, jni::ToJavaString(env, ppInfo.GetRatingFormatted()),
jni::ToJavaString(env, ppInfo.GetApproximatePricing()),
jni::ToJavaString(env, ppInfo.GetSponsoredBookingUrl()),
jni::ToJavaString(env, ppInfo.GetSponsoredDescriptionUrl()));
return env->NewObject(g_hotelClass, g_hotelClassConstructor,
jni::ToJavaString(env, ppInfo.GetRatingFormatted()),
jni::ToJavaString(env, ppInfo.GetApproximatePricing()),
jni::ToJavaString(env, ppInfo.GetSponsoredBookingUrl()),
jni::ToJavaString(env, ppInfo.GetSponsoredDescriptionUrl()));
}
// static void nativeRequestPrice(String id, String currencyCode);
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_widget_placepage_SponsoredHotel_nativeRequestPrice(JNIEnv * env, jclass clazz, jstring id, jstring currencyCode)
JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_SponsoredHotel_nativeRequestPrice(
JNIEnv * env, jclass clazz, jstring id, jstring currencyCode)
{
PrepareClassRefs(env, clazz);
string const hotelId = jni::ToNativeString(env, id);
string const code = jni::ToNativeString(env, currencyCode);
g_framework->RequestBookingMinPrice(hotelId, code, [hotelId](string const & price, string const & currency)
{
GetPlatform().RunOnGuiThread([=]()
{
g_framework->RequestBookingMinPrice(hotelId, code, [hotelId](string const & price,
string const & currency) {
GetPlatform().RunOnGuiThread([=]() {
JNIEnv * env = jni::GetEnv();
env->CallStaticVoidMethod(g_hotelClass, g_priceCallback, jni::ToJavaString(env, hotelId),
jni::ToJavaString(env, price),
jni::ToJavaString(env, currency));
jni::ToJavaString(env, price), jni::ToJavaString(env, currency));
});
});
}
} // extern "C"
// static void nativeRequestInfo(String id, String locale);
JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_SponsoredHotel_nativeRequestInfo(
JNIEnv * env, jclass clazz, jstring id, jstring locale)
{
PrepareClassRefs(env, clazz);
string const hotelId = jni::ToNativeString(env, id);
string const code = jni::ToNativeString(env, locale);
g_framework->RequestBookingInfo(hotelId, code, [hotelId](
BookingApi::HotelInfo const & hotelInfo) {
GetPlatform().RunOnGuiThread([=]() {
JNIEnv * env = jni::GetEnv();
auto description = jni::ToJavaString(env, hotelInfo.m_description);
auto photos =
jni::ToJavaArray(env, g_imageClass, hotelInfo.m_photos,
[](JNIEnv * env, BookingApi::HotelPhotoUrls const & item) {
return env->NewObject(g_imageClass, g_imageConstructor,
jni::ToJavaString(env, item.m_original),
jni::ToJavaString(env, item.m_small));
});
auto facilities =
jni::ToJavaArray(env, g_facilityTypeClass, hotelInfo.m_facilities,
[](JNIEnv * env, BookingApi::Facility const & item) {
return env->NewObject(g_facilityTypeClass, g_facilityConstructor,
jni::ToJavaString(env, item.m_id),
jni::ToJavaString(env, item.m_localizedName));
});
auto reviews = jni::ToJavaArray(
env, g_reviewClass, hotelInfo.m_reviews,
[](JNIEnv * env, BookingApi::HotelReview const & item) {
return env->NewObject(
g_reviewClass, g_reviewConstructor, jni::ToJavaString(env, item.m_reviewNeutral),
jni::ToJavaString(env, item.m_reviewPositive),
jni::ToJavaString(env, item.m_reviewNegative),
jni::ToJavaString(env, item.m_author), jni::ToJavaString(env, item.m_authorPictUrl),
item.m_rating,
time_point_cast<milliseconds>(item.m_date).time_since_epoch().count());
});
auto nearby = env->NewObjectArray(0, g_nearbyObjectClass, 0);
env->CallStaticVoidMethod(g_hotelClass, g_infoCallback, jni::ToJavaString(env, hotelId),
env->NewObject(g_hotelInfoClass, g_hotelInfoConstructor,
description, photos, facilities, reviews, nearby));
});
});
}
} // extern "C"

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/bg_placepage_rating_positive"/>
<size
android:height="@dimen/placepage_margin_rating"
android:width="@dimen/placepage_margin_rating"/>
</shape>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/bg_placepage_rating_positive_night"/>
<size
android:height="@dimen/placepage_margin_rating"
android:width="@dimen/placepage_margin_rating"/>
</shape>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/bg_placepage_rating_negative"/>
<size
android:height="@dimen/placepage_margin_rating"
android:width="@dimen/placepage_margin_rating"/>
</shape>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/bg_placepage_rating_negative_night"/>
<size
android:height="@dimen/placepage_margin_rating"
android:width="@dimen/placepage_margin_rating"/>
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:width="@dimen/margin_quarter"
android:height="@dimen/margin_quarter"/>
<solid android:color="@android:color/transparent"/>
</shape>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFF"
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
</vector>

View file

@ -0,0 +1,8 @@
<vector android:height="10dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0"
android:width="10dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFF44336"
android:pathData="M19,13H5v-2h14v2z"/>
</vector>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/bg_circle_red"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
<item
android:drawable="@drawable/ic_minus_red"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
</layer-list>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/bg_circle_red_night"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
<item
android:drawable="@drawable/ic_minus_red"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
</layer-list>

View file

@ -0,0 +1,8 @@
<vector android:height="10dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0"
android:width="10dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF578B2D"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/bg_circle_green"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
<item
android:drawable="@drawable/ic_plus_green"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
</layer-list>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/bg_circle_green_night"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
<item
android:drawable="@drawable/ic_plus_green"
android:left="@dimen/margin_eighth"
android:right="@dimen/margin_eighth"
android:bottom="@dimen/margin_eighth"
android:top="@dimen/margin_eighth"/>
</layer-list>

View file

@ -47,6 +47,12 @@
android:layout_toLeftOf="@id/anchor_center"
android:layout_toStartOf="@id/anchor_center"
android:orientation="vertical">
<include layout="@layout/place_page_hotel_gallery"/>
<include layout="@layout/place_page_hotel_facilities"/>
<include layout="@layout/place_page_hotel_description"/>
<include layout="@layout/place_page_placename"/>
<include layout="@layout/place_page_entrance"/>
@ -82,7 +88,13 @@
<include layout="@layout/place_page_cuisine"/>
<include layout="@layout/place_page_hotel_nearby"/>
<include layout="@layout/place_page_hotel_rating"/>
<!--TODO: remove this after booking_api.cpp will be done-->
<include layout="@layout/place_page_more"/>
</LinearLayout>
</RelativeLayout>

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<android.support.v4.view.ViewPager
android:id="@+id/vp__image"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<include
layout="@layout/toolbar_transparent"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_half"
android:layout_marginEnd="@dimen/margin_base"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
android:layout_gravity="bottom">
<TextView
android:id="@+id/tv__description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_half"
android:textColor="@color/white_primary"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:maxLines="1"
tools:text="Staff, rooftop view, location, free bike…"/>
<RelativeLayout
android:id="@+id/rl__user_block"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider_gallery"/>
<ImageView
android:id="@+id/iv__avatar"
android:layout_width="@dimen/track_circle_size"
android:layout_height="@dimen/track_circle_size"
android:layout_marginTop="@dimen/margin_half"
android:layout_below="@id/divider"
android:layout_marginRight="@dimen/margin_half"
android:layout_marginEnd="@dimen/margin_half"
tools:src="@drawable/img_editor_medal"/>
<TextView
android:id="@+id/tv__name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half"
android:layout_toRightOf="@id/iv__avatar"
android:layout_toEndOf="@id/iv__avatar"
android:layout_below="@id/divider"
android:maxLines="1"
android:textColor="@color/white_primary"
android:textAppearance="@style/MwmTextAppearance.Body1"
tools:text="Polina"/>
<TextView
android:id="@+id/tv__source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/iv__avatar"
android:layout_toEndOf="@id/iv__avatar"
android:layout_below="@id/tv__name"
android:maxLines="1"
android:textColor="@color/white_primary"
android:textAppearance="@style/MwmTextAppearance.Body4"
tools:text="via Booking"/>
<TextView
android:id="@+id/tv__date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/tv__source"
android:layout_toEndOf="@id/tv__source"
android:layout_alignBaseline="@id/tv__source"
android:gravity="end"
android:maxLines="1"
android:textColor="@color/white_primary"
android:textAppearance="@style/MwmTextAppearance.Body4"
tools:text="Jule 8, 2016"/>
</RelativeLayout>
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<ImageView
android:id="@+id/iv__image"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv__gallery"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:paddingTop="@dimen/margin_half_plus"
tools:listitem="@layout/item_image"/>
</LinearLayout>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?cardBackground">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv__review"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_comment"/>
</LinearLayout>

View file

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:id="@+id/v__divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:background="?dividerHorizontal"/>
<TextView
android:id="@+id/tv__user_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
android:layout_toLeftOf="@+id/tv__user_rating"
android:layout_toStartOf="@+id/tv__user_rating"
android:layout_below="@id/v__divider"
android:textAppearance="@style/MwmTextAppearance.Body1"
tools:text="Аleksey"/>
<TextView
android:id="@+id/tv__comment_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:layout_below="@id/tv__user_name"
android:textAppearance="@style/MwmTextAppearance.Body4"
tools:text="March 29, 2016"/>
<TextView
android:id="@+id/tv__user_rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@id/v__divider"
android:textAppearance="@style/MwmTextAppearance.Headline"
tools:text="9.2"/>
<TextView
android:id="@+id/tv__review"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:layout_below="@id/tv__comment_date"
android:textAppearance="@style/MwmTextAppearance.Body3.Primary"
android:visibility="gone"
tools:text="Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly."/>
<LinearLayout
android:id="@+id/ll__positive_review"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv__comment_date">
<ImageView
android:layout_width="@dimen/margin_base_plus"
android:layout_height="@dimen/margin_base_plus"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:src="?ppPositive"/>
<TextView
android:id="@+id/tv__positive_review"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_double"
android:layout_marginStart="@dimen/margin_double"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:paddingTop="@dimen/margin_eighth"
android:textAppearance="@style/MwmTextAppearance.Body3.Primary"
tools:text="Interesting place among SoHo, Little Italy and China town. Modern design. Great view from roof. Near subway. Free refreshment every afternoon. The staff was very friendly."/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll__negative_review"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/ll__positive_review">
<ImageView
android:id="@+id/iv__negative_review"
android:layout_width="@dimen/margin_base_plus"
android:layout_height="@dimen/margin_base_plus"
android:layout_marginBottom="@dimen/margin_base"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:src="?ppNegative"/>
<TextView
android:id="@+id/tv__negative_review"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_double"
android:layout_marginStart="@dimen/margin_double"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginEnd="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:paddingTop="@dimen/margin_eighth"
android:textAppearance="@style/MwmTextAppearance.Body3.Primary"
tools:text="Little bit noise from outsideLittle bit noise from outside"/>
</LinearLayout>
</RelativeLayout>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/height_block_base"
android:orientation="horizontal"
android:gravity="center_vertical"
android:background="?clickableBackground"
android:clickable="true"
tools:visibility="visible">
<ImageView
android:id="@+id/iv__icon"
style="@style/PlacePageMetadataIcon"
android:src="@drawable/ic_entrance"/>
<TextView
android:id="@+id/tv__facility"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body3.Primary"
tools:text="Pets are allowed on request"/>
</LinearLayout>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="@dimen/placepage_hotel_gallery_width"
android:layout_height="@dimen/placepage_hotel_gallery_height"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground">
<ImageView
android:id="@+id/iv__image"
android:layout_width="@dimen/placepage_hotel_gallery_width"
android:layout_height="@dimen/placepage_hotel_gallery_height"
tools:src="@color/base_green"/>
<TextView
android:id="@+id/tv__more"
style="@style/PlacePageGalleryText"
android:text="@string/placepage_more_button"
android:visibility="gone"
tools:visibility="visible"/>
</FrameLayout>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/gallery_image_height"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground">
<ImageView
android:id="@+id/iv__image"
android:layout_width="match_parent"
android:layout_height="@dimen/gallery_image_height"
tools:src="@color/base_green"/>
</FrameLayout>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/PlacePageMetadataText.Button"
android:height="@dimen/height_block_base"
android:background="?clickableBackground"
android:gravity="center"
android:text="@string/placepage_more_reviews_button"/>

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:paddingTop="@dimen/margin_half_plus"
android:paddingBottom="@dimen/margin_half_plus"
android:paddingRight="@dimen/margin_base"
android:paddingEnd="@dimen/margin_base"
android:paddingLeft="@dimen/margin_base"
android:paddingStart="@dimen/margin_base"
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackground"
tools:background="#4000FFFF">
<ImageView
android:id="@+id/iv__icon"
android:layout_width="@dimen/placepage_hotel_nearby_icon_size"
android:layout_height="@dimen/placepage_hotel_nearby_icon_size"
android:layout_centerVertical="true"
tools:src="@color/base_green"/>
<LinearLayout
android:id="@+id/ll__info"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_double"
android:layout_marginStart="@dimen/margin_double"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/iv__icon"
android:layout_toEndOf="@id/iv__icon"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv__title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:textAppearance="@style/MwmTextAppearance.Body1"
tools:text="Bowery"/>
<TextView
android:id="@+id/tv__type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_quarter"
android:maxLines="1"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="Subway Station"/>
</LinearLayout>
<TextView
android:id="@+id/tv__distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/ll__info"
android:layout_toEndOf="@id/ll__info"
android:maxLines="1"
android:textAppearance="@style/MwmTextAppearance.PlacePage.Accent"
android:gravity="end"
tools:text="800 ft"/>
</RelativeLayout>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/placepage_margin_rating"
android:paddingBottom="@dimen/margin_base"
android:paddingLeft="@dimen/margin_base"
android:paddingRight="@dimen/margin_base"
android:background="?ppRatingBackground">
<TextView
android:id="@+id/tv__place_hotel_rating"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:textColor="?ppRatingText"
tools:text="Rating: 8.7 (Excellent)"/>
<TextView
android:id="@+id/tv__place_hotel_rating_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="Based on 848 hotel reviews"/>
</LinearLayout>

View file

@ -27,6 +27,12 @@
android:layout_marginBottom="@dimen/margin_half"
tools:visibility="gone"/>
<include layout="@layout/place_page_hotel_gallery"/>
<include layout="@layout/place_page_hotel_facilities"/>
<include layout="@layout/place_page_hotel_description"/>
<include layout="@layout/place_page_placename"/>
<include layout="@layout/place_page_opening_hours"/>
@ -49,6 +55,11 @@
<include layout="@layout/place_page_cuisine"/>
<include layout="@layout/place_page_hotel_nearby"/>
<include layout="@layout/place_page_hotel_rating"/>
<!--TODO: remove this after booking_api.cpp will be done-->
<include layout="@layout/place_page_more"/>
<include layout="@layout/divider_horizontal"/>

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_hotel_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minHeight="@dimen/height_block_base"
android:visibility="gone"
tools:background="#20FF0000"
tools:visibility="visible">
<TextView
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
style="@style/PlacePageTitleText"
android:text="@string/details"/>
<com.mapswithme.maps.widget.LineCountTextView
android:id="@+id/tv__place_hotel_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_half_plus"
android:layout_marginBottom="@dimen/margin_half_plus"
android:textAppearance="@style/MwmTextAppearance.Body3.Primary"
android:maxLines="@integer/pp_hotel_description_lines"
tools:text="One of our top picks in New York City. This boutique hotel in the Manhattan neighborhood of Nolita features a private rooftop and rooms with free WiFi. The Bowery subway station is 1 block from this New York hotel."/>
<TextView
android:id="@+id/tv__place_hotel_more"
style="@style/PlacePageMetadataText.Button"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:height="@dimen/height_block_base"
android:background="?clickableBackground"
android:gravity="center"
android:text="@string/placepage_more_button"/>
<include layout="@layout/divider_horizontal"/>
</LinearLayout>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_hotel_facilities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minHeight="@dimen/height_block_base"
android:visibility="gone"
tools:background="#4000FFFF"
tools:visibility="visible">
<TextView
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
style="@style/PlacePageTitleText"
android:text="@string/placepage_hotel_facilities"/>
<com.mapswithme.maps.widget.StaticGridView
android:id="@+id/gv__place_hotel_facilities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:numColumns="2"
tools:listitem="@layout/item_facility"/>
<TextView
android:id="@+id/tv__place_hotel_facilities_more"
style="@style/PlacePageMetadataText.Button"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:height="@dimen/height_block_base"
android:background="?clickableBackground"
android:gravity="center"
android:text="@string/placepage_more_button"/>
<include layout="@layout/divider_horizontal"/>
</LinearLayout>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_hotel_gallery"
android:layout_width="match_parent"
android:layout_height="@dimen/placepage_hotel_gallery_height"
android:orientation="horizontal"
android:minHeight="@dimen/placepage_hotel_gallery_height"
android:visibility="gone"
tools:background="#20FF0000"
tools:visibility="visible">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv__place_hotel_gallery"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_gallery"/>
</LinearLayout>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_hotel_nearby"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minHeight="@dimen/height_block_base"
android:visibility="gone"
tools:background="#4000FFFF"
tools:visibility="visible">
<include layout="@layout/divider_horizontal"/>
<TextView
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginTop="@dimen/margin_base"
style="@style/PlacePageTitleText"
android:text="@string/placepage_hotel_nearby"/>
<com.mapswithme.maps.widget.StaticGridView
android:id="@+id/gv__place_hotel_nearby"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_quarter"
android:numColumns="1"
tools:listitem="@layout/item_nearby"/>
</LinearLayout>

View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll__place_hotel_rating"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/placepage_margin_rating"
android:paddingBottom="@dimen/margin_base"
android:paddingLeft="@dimen/margin_base"
android:paddingRight="@dimen/margin_base"
android:background="?ppRatingBackground">
<TextView
android:id="@+id/tv__place_hotel_rating"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body1"
android:textColor="?ppRatingText"
tools:text="Rating: 8.7 (Excellent)"/>
<TextView
android:id="@+id/tv__place_hotel_rating_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="Based on 848 hotel reviews"/>
</LinearLayout>
<com.mapswithme.maps.widget.StaticGridView
android:id="@+id/gv__place_hotel_review"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="1"
tools:listitem="@layout/item_comment"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:background="?dividerHorizontal"/>
<TextView
android:id="@+id/tv__place_hotel_reviews_more"
style="@style/PlacePageMetadataText.Button"
android:height="@dimen/height_block_base"
android:background="?clickableBackground"
android:gravity="center"
android:text="@string/placepage_more_reviews_button"/>
</LinearLayout>

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--TODO: remove this layout after booking_api.cpp will be done-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll__more"

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
style="@style/MwmWidget.ToolbarStyle"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/MwmWidget.ToolbarTheme.Transparent"/>

View file

@ -879,6 +879,7 @@
<string name="minute">мин</string>
<string name="placepage_place_description">Описание</string>
<string name="placepage_more_button">Ещё</string>
<string name="placepage_more_reviews_button">Ещё отзывы</string>
<string name="bookingcom_book_button">Забронировать</string>
<string name="placepage_call_button">Позвонить</string>
<string name="placepage_edit_bookmark_button">Редактировать метку</string>
@ -964,4 +965,8 @@
<string name="whats_new_route_profile_message">На пеших и веломаршрутах отображается профиль рельефа.</string>
<string name="whats_new_booking_improve_title">Экономь на бронировании отеля</string>
<string name="whats_new_booking_improve_message">Результаты поиска отелей на карте показывают ценовую категорию.\nОтелей для бронирования стало на 110 000 больше.</string>
<!-- For place page hotel facilities block -->
<string name="placepage_hotel_facilities">Удобства</string>
<!-- For place page hotel nearby block -->
<string name="placepage_hotel_nearby">Рядом</string>
</resources>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Android Strings File -->
<!-- Generated by Twine 0.6.0 -->
<!-- Language: v16 -->
<resources>
<!-- SECTION: Strings -->
<!-- SECTION: Routing dialogs strings -->
<!-- SECTION: Strings for downloading map from search -->
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MwmTextAppearance.PlacePage.Title"
parent="MwmTextAppearance.Body3">
<item name="android:fontFamily">sans-serif-medium</item>
</style>
</resources>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Android Strings File -->
<!-- Generated by Twine 0.6.0 -->
<!-- Language: w840dp -->
<resources>
<!-- SECTION: Strings -->
<!-- SECTION: Routing dialogs strings -->
<!-- SECTION: Strings for downloading map from search -->
</resources>

View file

@ -32,6 +32,10 @@
<color name="divider">#1E000000</color>
<color name="divider_night">#1EFFFFFF</color>
<color name="divider_gallery">#66FFFFFF</color>
<color name="text_placepage_rating">#568B2E</color>
<color name="text_placepage_rating_night">#46A046</color>
<!-- Backgrounds -->
<color name="bg_window">#FFEEEEEE</color>
@ -59,6 +63,13 @@
<color name="bg_azimut_arrow">#1D414651</color>
<color name="fg_azimut_arrow">#FFFFFFFF</color>
<color name="bg_placepage_rating">#F1F8E9</color>
<color name="bg_placepage_rating_night">#1EF0FAEB</color>
<color name="bg_placepage_rating_positive">#DCEDC8</color>
<color name="bg_placepage_rating_positive_night">#1EF0FAEB</color>
<color name="bg_placepage_rating_negative">#FFCDD2</color>
<color name="bg_placepage_rating_negative_night">#1EFFEBF0</color>
<!-- Buttons -->
<color name="button">@color/button_normal</color>
<color name="button_night">@color/button_normal_night</color>

View file

@ -145,6 +145,16 @@
<dimen name="altitude_chart_image_height">40dp</dimen>
<dimen name="altitude_chart_image_width">232dp</dimen>
<!-- Gallery-->
<dimen name="placepage_hotel_gallery_height">100dp</dimen>
<dimen name="placepage_hotel_gallery_width">150dp</dimen>
<dimen name="gallery_image_height">84dp</dimen>
<!-- Nearby-->
<dimen name="placepage_hotel_nearby_height">64dp</dimen>
<dimen name="placepage_hotel_nearby_icon_size">24dp</dimen>
<!-- Rating-->
<dimen name="placepage_margin_rating">20dp</dimen>
</resources>

View file

@ -2,6 +2,7 @@
<resources>
<integer name="pp_title_lines">5</integer>
<integer name="pp_buttons_max">4</integer>
<integer name="pp_hotel_description_lines">5</integer>
<integer name="sharing_initial_rows">2</integer>
</resources>
</resources>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="place_page_booking_rating_base">
<item quantity="zero">Based on %d hotel reviews</item>
<item quantity="one">Based on %d hotel reviews</item>
<item quantity="two">Based on %d hotel reviews</item>
<item quantity="few">Based on %d hotel reviews</item>
<item quantity="many">Based on %d hotel reviews</item>
<item quantity="other">Based on %d hotel reviews</item>
</plurals>
</resources>

View file

@ -883,6 +883,7 @@
<string name="minute">min</string>
<string name="placepage_place_description">Description</string>
<string name="placepage_more_button">More</string>
<string name="placepage_more_reviews_button">More Reviews</string>
<string name="bookingcom_book_button">Book</string>
<string name="placepage_call_button">Call</string>
<string name="placepage_edit_bookmark_button">Edit Bookmark</string>
@ -968,4 +969,8 @@
<string name="whats_new_route_profile_message">For pedestrian and bike routes we now display the elevation profile.</string>
<string name="whats_new_booking_improve_title">Save when booking hotels</string>
<string name="whats_new_booking_improve_message">Search results for hotels now contain the price category.\nWe also added more than 110,000 hotels.</string>
<!-- For place page hotel facilities block -->
<string name="placepage_hotel_facilities">Facilities</string>
<!-- For place page hotel nearby block -->
<string name="placepage_hotel_nearby">Nearby</string>
</resources>

View file

@ -59,6 +59,23 @@
<item name="android:textAppearance">@style/MwmTextAppearance.PlacePage.Accent</item>
</style>
<style name="PlacePageTitleText">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textAppearance">@style/MwmTextAppearance.PlacePage.Title</item>
</style>
<style name="PlacePageGalleryText">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">center</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@color/white_primary</item>
<item name="android:textAllCaps">true</item>
<item name="android:drawableRight">@drawable/ic_chevron_right_white</item>
<item name="android:drawableEnd" tools:targetApi="jelly_bean_mr1">@drawable/ic_chevron_right_white</item>
</style>
<style name="PlacePageMetadataIcon">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
@ -66,4 +83,4 @@
<item name="android:layout_marginEnd" tools:targetApi="jelly_bean_mr1">@dimen/margin_base</item>
<item name="android:layout_marginRight">@dimen/margin_base</item>
</style>
</resources>
</resources>

View file

@ -53,6 +53,11 @@
<item name="android:textColor">?android:textColorSecondary</item>
</style>
<style name="MwmTextAppearance.Body3.Primary">
<item name="android:textSize">@dimen/text_size_body_3</item>
<item name="android:textColor">?android:textColorPrimary</item>
</style>
<style name="MwmTextAppearance.Body3.Light">
<item name="android:textColor">?android:textColorPrimaryInverse</item>
</style>
@ -116,6 +121,10 @@
<item name="android:textStyle">bold</item>
</style>
<style name="MwmTextAppearance.RoutingDimension.Inline" parent="MwmTextAppearance.RoutingNumber">
<item name="android:textSize">@dimen/text_size_routing_dimension_inline</item>
</style>
<style name="MwmTextAppearance.RoutingDetail">
<item name="android:textSize">@dimen/text_size_routing_plan_detail</item>
<item name="android:fontFamily" tools:ignore="NewApi">@string/robotoMedium</item>
@ -143,13 +152,14 @@
<item name="android:textSize">@dimen/text_size_nav_circle_exit</item>
</style>
<style name="MwmTextAppearance.PlacePage"
parent="MwmTextAppearance.Body1"/>
<style name="MwmTextAppearance.PlacePage" parent="MwmTextAppearance.Body1"/>
<style name="MwmTextAppearance.PlacePage.Accent">
<item name="android:textColor">?colorAccent</item>
</style>
<style name="MwmTextAppearance.PlacePage.Title" parent="MwmTextAppearance.Body3"/>
<style name="MwmTextAppearance.Editor">
</style>
@ -161,4 +171,4 @@
<style name="MwmTextAppearance.Editor.Buttons">
<item name="android:textSize">@dimen/text_size_body_3</item>
</style>
</resources>
</resources>

View file

@ -16,8 +16,7 @@
<item name="android:layout_marginLeft">0dp</item>
</style>
<style name="MwmWidget.MapButton"
parent="android:Widget.ImageButton">
<style name="MwmWidget.MapButton" parent="android:Widget.ImageButton">
<item name="android:scaleType">center</item>
<item name="android:layout_height">64dp</item>
<item name="android:layout_width">64dp</item>
@ -53,73 +52,56 @@
</style>
<style name="MwmWidget.Floating">
<item name="android:elevation"
tools:ignore="NewApi">@dimen/appbar_elevation
</item>
<item name="android:elevation" tools:ignore="NewApi">@dimen/appbar_elevation</item>
</style>
<style name="MwmWidget.Floating.Panel">
<item name="android:background">?panel</item>
</style>
<style
name="MwmWidget.PlacePage.EditText"
parent="Widget.AppCompat.EditText">
<style name="MwmWidget.PlacePage.EditText" parent="Widget.AppCompat.EditText">
<item name="android:imeOptions">actionDone</item>
<item name="android:textAppearance">@style/MwmTextAppearance.PlacePage</item>
<item name="android:textColorHint">?secondary</item>
<item name="android:textCursorDrawable">@null</item>
<item name="android:fontFamily"
tools:ignore="NewApi">@string/robotoRegular
</item>
<item name="android:fontFamily" tools:ignore="NewApi">@string/robotoRegular</item>
</style>
<style
name="MwmWidget.ToolbarStyle"
parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<style name="MwmWidget.ToolbarStyle" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:background">?colorPrimary</item>
<item name="android:elevation"
tools:ignore="NewApi">@dimen/appbar_elevation
</item>
<item name="android:elevation" tools:ignore="NewApi">@dimen/appbar_elevation</item>
<item name="android:displayOptions">homeAsUp|showTitle</item>
<item name="contentInsetStart">72dp</item>
<item name="android:titleTextAppearance"
tools:ignore="NewApi">@style/MwmTextAppearance.Toolbar.Title
</item>
<item name="android:titleTextAppearance" tools:ignore="NewApi">@style/MwmTextAppearance.Toolbar.Title</item>
<item name="titleTextAppearance">@style/MwmTextAppearance.Toolbar.Title</item>
<item name="contentInsetLeft">72dp</item>
<item name="android:contentInsetStart"
tools:ignore="NewApi">72dp
</item>
<item name="android:contentInsetLeft"
tools:ignore="NewApi">72dp
</item>
<item name="android:contentInsetStart" tools:ignore="NewApi">72dp</item>
<item name="android:contentInsetLeft" tools:ignore="NewApi">72dp</item>
</style>
<style name="MwmWidget.ToolbarStyle.Light">
<item name="android:titleTextAppearance"
tools:targetApi="lollipop">@style/MwmTextAppearance.Toolbar.Title.Light
</item>
<item name="android:titleTextAppearance" tools:targetApi="lollipop">@style/MwmTextAppearance.Toolbar.Title.Light</item>
<item name="titleTextAppearance">@style/MwmTextAppearance.Toolbar.Title.Light</item>
</style>
<style
name="MwmWidget.ToolbarTheme"
parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<style name="MwmWidget.ToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:gravity">center_vertical</item>
<item name="colorAccent">@android:color/white</item>
</style>
<style
name="MwmWidget.ToolbarTheme.Light"
parent="ThemeOverlay.AppCompat.ActionBar">
<style name="MwmWidget.ToolbarTheme.Light" parent="ThemeOverlay.AppCompat.ActionBar">
<item name="android:gravity">center_vertical</item>
<item name="colorAccent">@color/bg_window_night</item>
</style>
<style
name="MwmWidget.ListView"
parent="Widget.AppCompat.ListView">
<style name="MwmWidget.ToolbarTheme.Transparent" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:gravity">center_vertical</item>
<item name="colorAccent">@android:color/white</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="windowActionBarOverlay">true</item>
</style>
<style name="MwmWidget.ListView" parent="Widget.AppCompat.ListView">
<item name="android:fadingEdge">none</item>
<item name="android:divider">@color/divider</item>
<item name="android:background">@null</item>
@ -129,8 +111,7 @@
<item name="android:cacheColorHint">@android:color/transparent</item>
</style>
<style name="MwmWidget.TextView"
parent="android:Widget.TextView">
<style name="MwmWidget.TextView" parent="android:Widget.TextView">
<item name="android:background">@android:color/transparent</item>
</style>
@ -203,8 +184,7 @@
<item name="android:foreground">@drawable/shadow_top</item>
</style>
<style name="MwmWidget.RatingBar"
parent="android:Widget.RatingBar">
<style name="MwmWidget.RatingBar" parent="android:Widget.RatingBar">
<item name="android:progressDrawable">@drawable/rating_bar</item>
<item name="android:indeterminateDrawable">@drawable/rating_bar</item>
</style>
@ -240,9 +220,7 @@
<item name="android:textAppearance">@style/MwmTextAppearance.Toolbar.Title.Button</item>
</style>
<style
name="MwmWidget.SearchNavigationButton"
parent="android:Widget.ImageButton">
<style name="MwmWidget.SearchNavigationButton" parent="android:Widget.ImageButton">
<item name="android:scaleType">center</item>
<item name="android:layout_height">44dp</item>
<item name="android:layout_width">44dp</item>

View file

@ -24,6 +24,10 @@
<attr name="ppPreviewHeadOpen" format="reference"/>
<attr name="ppPreviewHeadClosed" format="reference"/>
<attr name="ppArrowDrawable" format="reference"/>
<attr name="ppRatingBackground" format="color"/>
<attr name="ppRatingText" format="color"/>
<attr name="ppPositive" format="reference"/>
<attr name="ppNegative" format="reference"/>
<attr name="routingSlot" format="reference"/>
<attr name="routingSlotPressed" format="reference"/>

View file

@ -75,6 +75,11 @@
<item name="routingButtonHint">@color/routing_button_tint</item>
<item name="routingButtonPressedHint">@color/routing_button_pressed_tint</item>
<item name="ppRatingBackground">@color/bg_placepage_rating</item>
<item name="ppRatingText">@color/text_placepage_rating</item>
<item name="ppPositive">@drawable/ic_positive_review</item>
<item name="ppNegative">@drawable/ic_negative_review</item>
</style>
<!-- Night theme -->
@ -152,5 +157,10 @@
<item name="routingButtonHint">@color/routing_button_tint</item>
<item name="routingButtonPressedHint">@color/routing_button_pressed_tint</item>
<item name="ppRatingBackground">@color/bg_placepage_rating_night</item>
<item name="ppRatingText">@color/text_placepage_rating_night</item>
<item name="ppPositive">@drawable/ic_positive_review_night</item>
<item name="ppNegative">@drawable/ic_negative_review_night</item>
</style>
</resources>

View file

@ -153,4 +153,24 @@
<item name="newsMarker">@drawable/news_marker_night</item>
</style>
</resources>
<style name="MwmTheme.FullScreenGalleryActivity">
<item name="colorPrimary">@android:color/transparent</item>
<item name="android:colorPrimaryDark" tools:targetApi="lollipop">@android:color/black</item>
<item name="android:timePickerStyle" tools:targetApi="lollipop">@style/MwmWidget.Editor.TimePicker</item>
<item name="android:windowBackground">@null</item>
<item name="windowActionBar">false</item>
<item name="windowActionBarOverlay">true</item>
<item name="android:windowActionBarOverlay">true</item>
</style>
<style name="MwmTheme.Night.FullScreenGalleryActivity">
<item name="colorPrimary">@android:color/transparent</item>
<item name="android:colorPrimaryDark" tools:targetApi="lollipop">@android:color/black</item>
<item name="android:timePickerStyle" tools:targetApi="lollipop">@style/MwmWidget.Editor.TimePicker</item>
<item name="android:windowBackground">@null</item>
<item name="windowActionBar">false</item>
<item name="windowActionBarOverlay">true</item>
<item name="android:windowActionBarOverlay">true</item>
</style>
</resources>

View file

@ -0,0 +1,43 @@
package com.mapswithme.maps.base;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.v7.widget.Toolbar;
import com.mapswithme.maps.R;
import com.mapswithme.util.UiUtils;
public class BaseMwmExtraTitleActivity extends BaseMwmFragmentActivity
{
protected static final String EXTRA_TITLE = "activity_title";
@Override
@CallSuper
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
String title = "";
Bundle bundle = getIntent().getExtras();
if (bundle != null)
{
title = bundle.getString(EXTRA_TITLE);
}
Toolbar toolbar = getToolbar();
toolbar.setTitle(title);
UiUtils.showHomeUpButton(toolbar);
displayToolbarAsActionBar();
}
@Override
protected int getContentLayoutResId()
{
return R.layout.activity_fragment_and_toolbar;
}
@Override
protected int getFragmentContentResId()
{
return R.id.fragment_container;
}
}

View file

@ -0,0 +1,204 @@
package com.mapswithme.maps.gallery;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.BitmapImageViewTarget;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseMwmFragmentActivity;
import com.mapswithme.util.ThemeUtils;
import com.mapswithme.util.UiUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class FullScreenGalleryActivity extends BaseMwmFragmentActivity
implements ViewPager.OnPageChangeListener
{
public static final String EXTRA_IMAGES = "gallery_images";
public static final String EXTRA_POSITION = "gallery_position";
private List<Image> mImages;
private int mPosition;
private View mUserBlock;
private TextView mDescription;
private TextView mUserName;
private TextView mSource;
private TextView mDate;
private ImageView mAvatar;
private GalleryPageAdapter mGalleryPageAdapter;
public static void start(Context context, ArrayList<Image> images, int position)
{
final Intent i = new Intent(context, FullScreenGalleryActivity.class);
i.putParcelableArrayListExtra(EXTRA_IMAGES, images);
i.putExtra(EXTRA_POSITION, position);
context.startActivity(i);
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
Toolbar toolbar = getToolbar();
toolbar.setTitle("");
UiUtils.showHomeUpButton(toolbar);
displayToolbarAsActionBar();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
mUserBlock = findViewById(R.id.rl__user_block);
mDescription = (TextView) findViewById(R.id.tv__description);
mUserName = (TextView) findViewById(R.id.tv__name);
mSource = (TextView) findViewById(R.id.tv__source);
mDate = (TextView) findViewById(R.id.tv__date);
mAvatar = (ImageView) findViewById(R.id.iv__avatar);
readParameters();
if (mImages != null)
{
mGalleryPageAdapter = new GalleryPageAdapter(getSupportFragmentManager(), mImages);
final ViewPager viewPager = (ViewPager) findViewById(R.id.vp__image);
viewPager.addOnPageChangeListener(this);
viewPager.setAdapter(mGalleryPageAdapter);
viewPager.setCurrentItem(mPosition);
viewPager.post(new Runnable()
{
@Override
public void run()
{
onPageSelected(viewPager.getCurrentItem());
}
});
}
}
@Override
public int getThemeResourceId(String theme)
{
if (ThemeUtils.isDefaultTheme(theme))
return R.style.MwmTheme_FullScreenGalleryActivity;
if (ThemeUtils.isNightTheme(theme))
return R.style.MwmTheme_Night_FullScreenGalleryActivity;
throw new IllegalArgumentException("Attempt to apply unsupported theme: " + theme);
}
@Override
protected int getContentLayoutResId()
{
return R.layout.activity_full_screen_gallery;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
}
@Override
public void onPageSelected(int position)
{
updateInformation(mGalleryPageAdapter.getImage(position));
}
@Override
public void onPageScrollStateChanged(int state)
{
}
private void readParameters()
{
Bundle extras = getIntent().getExtras();
if (extras != null)
{
mImages = extras.getParcelableArrayList(EXTRA_IMAGES);
mPosition = extras.getInt(EXTRA_POSITION);
}
}
private void updateInformation(@NonNull Image image)
{
UiUtils.setTextAndHideIfEmpty(mDescription, image.getDescription());
UiUtils.setTextAndHideIfEmpty(mUserName, image.getUserName());
UiUtils.setTextAndHideIfEmpty(mSource, image.getSource());
updateDate(image);
updateUserAvatar(image);
updateUserBlock();
}
private void updateDate(Image image)
{
if (image.getDate() != null)
{
Date date = new Date(image.getDate());
mDate.setText(DateFormat.getMediumDateFormat(this).format(date));
UiUtils.show(mDate);
}
else
{
UiUtils.hide(mDate);
}
}
private void updateUserAvatar(Image image)
{
if (!TextUtils.isEmpty(image.getUserAvatar()))
{
UiUtils.show(mAvatar);
Glide.with(this)
.load(image.getUserAvatar())
.asBitmap()
.centerCrop()
.into(new BitmapImageViewTarget(mAvatar)
{
@Override
protected void setResource(Bitmap resource)
{
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(getResources(), resource);
circularBitmapDrawable.setCircular(true);
mAvatar.setImageDrawable(circularBitmapDrawable);
}
});
}
else
UiUtils.hide(mAvatar);
}
private void updateUserBlock()
{
if (UiUtils.isHidden(mUserName)
&& UiUtils.isHidden(mSource)
&& UiUtils.isHidden(mDate)
&& UiUtils.isHidden(mAvatar))
{
UiUtils.hide(mUserBlock);
}
else
{
UiUtils.show(mUserBlock);
}
}
}

View file

@ -0,0 +1,50 @@
package com.mapswithme.maps.gallery;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseMwmFragment;
public class FullScreenGalleryFragment extends BaseMwmFragment
{
static final String ARGUMENT_IMAGE = "argument_image";
@Nullable
private Image mImage;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_fullscreen_image, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
readArguments();
if (mImage != null)
{
ImageView imageView = (ImageView) view.findViewById(R.id.iv__image);
Glide.with(view.getContext())
.load(mImage.getUrl())
.into(imageView);
}
}
private void readArguments()
{
Bundle args = getArguments();
if (args != null)
mImage = args.getParcelable(ARGUMENT_IMAGE);
}
}

View file

@ -0,0 +1,29 @@
package com.mapswithme.maps.gallery;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import com.mapswithme.maps.base.BaseMwmExtraTitleActivity;
import java.util.ArrayList;
public class GalleryActivity extends BaseMwmExtraTitleActivity
{
public static final String EXTRA_IMAGES = "gallery_images";
public static void start(Context context, @NonNull ArrayList<Image> images, @NonNull String title)
{
final Intent i = new Intent(context, GalleryActivity.class);
i.putParcelableArrayListExtra(EXTRA_IMAGES, images);
i.putExtra(EXTRA_TITLE, title);
context.startActivity(i);
}
@Override
protected Class<? extends Fragment> getFragmentClass()
{
return GalleryFragment.class;
}
}

View file

@ -0,0 +1,65 @@
package com.mapswithme.maps.gallery;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseMwmFragment;
import com.mapswithme.maps.widget.recycler.GridDividerItemDecoration;
import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
import java.util.ArrayList;
public class GalleryFragment extends BaseMwmFragment implements RecyclerClickListener
{
private static final int NUM_COLUMNS = 3;
@Nullable
private ArrayList<Image> mImages;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_gallery, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
readArguments();
if (mImages != null)
{
RecyclerView rvGallery = (RecyclerView) view.findViewById(R.id.rv__gallery);
rvGallery.setLayoutManager(new GridLayoutManager(getContext(), NUM_COLUMNS));
rvGallery.setAdapter(new ImageAdapter(mImages, this));
Drawable divider = ContextCompat.getDrawable(getContext(), R.drawable.divider_transparent);
rvGallery.addItemDecoration(new GridDividerItemDecoration(divider, divider, NUM_COLUMNS));
}
}
private void readArguments()
{
final Bundle arguments = getArguments();
if (arguments == null)
return;
mImages = arguments.getParcelableArrayList(GalleryActivity.EXTRA_IMAGES);
}
@Override
public void onItemClick(View v, int position)
{
FullScreenGalleryActivity.start(getContext(), mImages, position);
}
}

View file

@ -0,0 +1,44 @@
package com.mapswithme.maps.gallery;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import java.util.List;
class GalleryPageAdapter extends FragmentStatePagerAdapter
{
@NonNull
private final List<Image> mImages;
GalleryPageAdapter(@NonNull FragmentManager fm, @NonNull List<Image> images)
{
super(fm);
mImages = images;
}
@Override
public Fragment getItem(int position)
{
Bundle args = new Bundle();
args.putParcelable(FullScreenGalleryFragment.ARGUMENT_IMAGE, mImages.get(position));
FullScreenGalleryFragment fragment = new FullScreenGalleryFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public int getCount()
{
return mImages.size();
}
@NonNull
Image getImage(int position)
{
return mImages.get(position);
}
}

View file

@ -0,0 +1,144 @@
package com.mapswithme.maps.gallery;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
public class Image implements Parcelable
{
@NonNull
private final String mUrl;
@NonNull
private final String mSmallUrl;
@Nullable
private String mDescription;
@Nullable
private String mUserName;
@Nullable
private String mUserAvatar;
@Nullable
private String mSource;
@Nullable
private Long mDate;
@SuppressWarnings("unused")
public Image(@NonNull String url, @NonNull String smallUrl)
{
this.mUrl = url;
this.mSmallUrl = smallUrl;
}
protected Image(Parcel in)
{
mUrl = in.readString();
mSmallUrl = in.readString();
mDescription = in.readString();
mUserName = in.readString();
mUserAvatar = in.readString();
mSource = in.readString();
mDate = (Long) in.readValue(Long.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeString(mUrl);
dest.writeString(mSmallUrl);
dest.writeString(mDescription);
dest.writeString(mUserName);
dest.writeString(mUserAvatar);
dest.writeString(mSource);
dest.writeValue(mDate);
}
@Override
public int describeContents()
{
return 0;
}
public static final Creator<Image> CREATOR = new Creator<Image>()
{
@Override
public Image createFromParcel(Parcel in)
{
return new Image(in);
}
@Override
public Image[] newArray(int size)
{
return new Image[size];
}
};
@NonNull
public String getUrl()
{
return mUrl;
}
@NonNull
public String getSmallUrl()
{
return mSmallUrl;
}
@Nullable
public String getDescription()
{
return mDescription;
}
public void setDescription(@Nullable String description)
{
this.mDescription = description;
}
@Nullable
String getUserName()
{
return mUserName;
}
@SuppressWarnings("unused")
public void setUserName(@Nullable String userName)
{
this.mUserName = userName;
}
@Nullable
String getUserAvatar()
{
return mUserAvatar;
}
@SuppressWarnings("unused")
public void setUserAvatar(@Nullable String userAvatar)
{
this.mUserAvatar = userAvatar;
}
@Nullable
public String getSource()
{
return mSource;
}
public void setSource(@Nullable String source)
{
this.mSource = source;
}
@Nullable
public Long getDate()
{
return mDate;
}
public void setDate(@Nullable Long date)
{
this.mDate = date;
}
}

View file

@ -0,0 +1,79 @@
package com.mapswithme.maps.gallery;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.mapswithme.maps.R;
import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
import java.util.ArrayList;
class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder>
{
@NonNull
private final ArrayList<Image> mItems;
@Nullable
private final RecyclerClickListener mListener;
ImageAdapter(@NonNull ArrayList<Image> images, @Nullable RecyclerClickListener listener)
{
mItems = images;
mListener = listener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
return new ViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_image, parent, false), mListener);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.bind(mItems.get(position), position);
}
@Override
public int getItemCount()
{
return mItems.size();
}
static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private ImageView mImage;
private final RecyclerClickListener mListener;
private int mPosition;
public ViewHolder(View itemView, RecyclerClickListener listener)
{
super(itemView);
mListener = listener;
itemView.setOnClickListener(this);
mImage = (ImageView) itemView.findViewById(R.id.iv__image);
}
@Override
public void onClick(View v)
{
if (mListener != null)
mListener.onItemClick(v, mPosition);
}
public void bind(Image image, int position)
{
mPosition = position;
Glide.with(mImage.getContext())
.load(image.getSmallUrl())
.centerCrop()
.into(mImage);
}
}
}

View file

@ -0,0 +1,121 @@
package com.mapswithme.maps.review;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
public class Review implements Parcelable
{
@Nullable
private final String mReview;
@Nullable
private final String mReviewPositive;
@Nullable
private final String mReviewNegative;
@NonNull
private final String mAuthor;
@NonNull
private final String mAuthorAvatar;
private final float mRating;
private final long mDate;
public Review(@Nullable String review, @Nullable String reviewPositive,
@Nullable String reviewNegative, @NonNull String author,
@NonNull String authorAvatar,
float rating, long date)
{
mReview = review;
mReviewPositive = reviewPositive;
mReviewNegative = reviewNegative;
mAuthor = author;
mAuthorAvatar = authorAvatar;
mRating = rating;
mDate = date;
}
protected Review(Parcel in)
{
mReview = in.readString();
mReviewPositive = in.readString();
mReviewNegative = in.readString();
mAuthor = in.readString();
mAuthorAvatar = in.readString();
mRating = in.readFloat();
mDate = in.readLong();
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeString(mReview);
dest.writeString(mReviewPositive);
dest.writeString(mReviewNegative);
dest.writeString(mAuthor);
dest.writeString(mAuthorAvatar);
dest.writeFloat(mRating);
dest.writeLong(mDate);
}
@Override
public int describeContents()
{
return 0;
}
public static final Creator<Review> CREATOR = new Creator<Review>()
{
@Override
public Review createFromParcel(Parcel in)
{
return new Review(in);
}
@Override
public Review[] newArray(int size)
{
return new Review[size];
}
};
@Nullable
public String getReview()
{
return mReview;
}
@Nullable
public String getReviewPositive()
{
return mReviewPositive;
}
@Nullable
public String getReviewNegative()
{
return mReviewNegative;
}
@NonNull
public String getAuthor()
{
return mAuthor;
}
@SuppressWarnings("unused")
@NonNull
public String getAuthorAvatar()
{
return mAuthorAvatar;
}
public float getRating()
{
return mRating;
}
public long getDate()
{
return mDate;
}
}

View file

@ -0,0 +1,37 @@
package com.mapswithme.maps.review;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import com.mapswithme.maps.base.BaseMwmExtraTitleActivity;
import java.util.ArrayList;
public class ReviewActivity extends BaseMwmExtraTitleActivity
{
static final String EXTRA_REVIEWS = "review_items";
static final String EXTRA_RATING = "review_rating";
static final String EXTRA_RATING_BASE = "review_rating_base";
static final String EXTRA_RATING_URL = "review_rating_url";
public static void start(Context context, @NonNull ArrayList<Review> items,
@NonNull String title, @NonNull String rating, int ratingBase,
@NonNull String url)
{
final Intent i = new Intent(context, ReviewActivity.class);
i.putParcelableArrayListExtra(EXTRA_REVIEWS, items);
i.putExtra(EXTRA_TITLE, title);
i.putExtra(EXTRA_RATING, rating);
i.putExtra(EXTRA_RATING_BASE, ratingBase);
i.putExtra(EXTRA_RATING_URL, url);
context.startActivity(i);
}
@Override
protected Class<? extends Fragment> getFragmentClass()
{
return ReviewFragment.class;
}
}

View file

@ -0,0 +1,217 @@
package com.mapswithme.maps.review;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.mapswithme.maps.R;
import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
import com.mapswithme.util.UiUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.BaseViewHolder>
{
private static final int MAX_COUNT = 15;
private static final int VIEW_TYPE_REVIEW = 0;
private static final int VIEW_TYPE_MORE = 1;
private static final int VIEW_TYPE_RATING = 2;
@NonNull
private final ArrayList<Review> mItems;
@Nullable
private final RecyclerClickListener mListener;
@NonNull
private final String mRating;
private final int mRatingBase;
ReviewAdapter(@NonNull ArrayList<Review> images, @Nullable RecyclerClickListener listener,
@NonNull String rating,
int ratingBase)
{
mItems = images;
mListener = listener;
mRating = rating;
mRatingBase = ratingBase;
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
if (viewType == VIEW_TYPE_REVIEW)
return new ReviewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_comment, parent, false), mListener);
if (viewType == VIEW_TYPE_MORE)
return new MoreHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_more_button, parent, false), mListener);
return new RatingHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_rating, parent, false), mListener);
}
@Override
public void onBindViewHolder(BaseViewHolder holder, int position)
{
int positionNoHeader = position - 1;
if (position == 0)
((RatingHolder) holder).bind(mRating, mRatingBase);
else if (positionNoHeader < mItems.size())
holder.bind(mItems.get(positionNoHeader), positionNoHeader);
else
holder.bind(null, positionNoHeader);
}
@Override
public int getItemCount()
{
if (mItems.size() > MAX_COUNT)
// 1 overall rating item + MAX_COUNT user reviews + 1 "more reviews" item
return MAX_COUNT + 2;
// 1 overall rating item + count of user reviews + 1 "more reviews" item
return mItems.size() + 2;
}
@Override
public int getItemViewType(int position)
{
int positionNoHeader = position - 1;
if (position == 0)
return VIEW_TYPE_RATING;
if (positionNoHeader == mItems.size())
return VIEW_TYPE_MORE;
return VIEW_TYPE_REVIEW;
}
static abstract class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private final RecyclerClickListener mListener;
private int mPosition;
BaseViewHolder(View itemView, RecyclerClickListener listener)
{
super(itemView);
mListener = listener;
}
@Override
public void onClick(View v)
{
if (mListener != null)
mListener.onItemClick(v, mPosition);
}
@CallSuper
public void bind(Review item, int position)
{
mPosition = position;
}
}
private static class ReviewHolder extends BaseViewHolder
{
final View mDivider;
final TextView mUserName;
final TextView mCommentDate;
final TextView mRating;
final TextView mReview;
final View mPositiveReview;
final TextView mTvPositiveReview;
final View mNegativeReview;
final TextView mTvNegativeReview;
ReviewHolder(View itemView, RecyclerClickListener listener)
{
super(itemView, listener);
mDivider = itemView.findViewById(R.id.v__divider);
mUserName = (TextView) itemView.findViewById(R.id.tv__user_name);
mCommentDate = (TextView) itemView.findViewById(R.id.tv__comment_date);
mRating = (TextView) itemView.findViewById(R.id.tv__user_rating);
mReview = (TextView) itemView.findViewById(R.id.tv__review);
mPositiveReview = itemView.findViewById(R.id.ll__positive_review);
mTvPositiveReview = (TextView) itemView.findViewById(R.id.tv__positive_review);
mNegativeReview = itemView.findViewById(R.id.ll__negative_review);
mTvNegativeReview = (TextView) itemView.findViewById(R.id.tv__negative_review);
}
@Override
public void bind(Review item, int position)
{
super.bind(item, position);
UiUtils.showIf(position > 0, mDivider);
mUserName.setText(item.getAuthor());
Date date = new Date(item.getDate());
mCommentDate.setText(DateFormat.getMediumDateFormat(mCommentDate.getContext()).format(date));
mRating.setText(String.format(Locale.getDefault(), "%.1f", item.getRating()));
if (TextUtils.isEmpty(item.getReviewPositive()))
{
UiUtils.hide(mPositiveReview);
}
else
{
UiUtils.show(mPositiveReview);
mTvPositiveReview.setText(item.getReviewPositive());
}
if (TextUtils.isEmpty(item.getReviewNegative()))
{
UiUtils.hide(mNegativeReview);
}
else
{
UiUtils.show(mNegativeReview);
mTvNegativeReview.setText(item.getReviewNegative());
}
if (UiUtils.isHidden(mNegativeReview) && UiUtils.isHidden(mPositiveReview))
{
UiUtils.showIf(!TextUtils.isEmpty(item.getReview()), mReview);
}
else
{
UiUtils.hide(mReview);
}
}
}
private static class MoreHolder extends BaseViewHolder
{
MoreHolder(View itemView, RecyclerClickListener listener)
{
super(itemView, listener);
itemView.setOnClickListener(this);
}
}
private static class RatingHolder extends BaseViewHolder
{
final TextView mHotelRating;
final TextView mHotelRatingBase;
RatingHolder(View itemView, RecyclerClickListener listener)
{
super(itemView, listener);
mHotelRating = (TextView) itemView.findViewById(R.id.tv__place_hotel_rating);
mHotelRatingBase = (TextView) itemView.findViewById(R.id.tv__place_hotel_rating_base);
}
public void bind(String rating, int ratingBase)
{
mHotelRating.setText(rating);
mHotelRatingBase.setText(mHotelRatingBase.getContext().getResources()
.getQuantityString(R.plurals.place_page_booking_rating_base,
ratingBase, ratingBase));
}
}
}

View file

@ -0,0 +1,76 @@
package com.mapswithme.maps.review;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseMwmFragment;
import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
import java.util.ArrayList;
public class ReviewFragment extends BaseMwmFragment implements RecyclerClickListener
{
@Nullable
private ArrayList<Review> mItems;
@Nullable
private String mRating;
private int mRatingBase;
@Nullable
private String mUrl;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_review, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
readArguments();
if (mItems != null && mRating != null)
{
RecyclerView rvGallery = (RecyclerView) view.findViewById(R.id.rv__review);
rvGallery.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
rvGallery.setAdapter(new ReviewAdapter(mItems, this, mRating, mRatingBase));
}
}
private void readArguments()
{
final Bundle arguments = getArguments();
if (arguments == null)
return;
mItems = arguments.getParcelableArrayList(ReviewActivity.EXTRA_REVIEWS);
mRating = arguments.getString(ReviewActivity.EXTRA_RATING);
mRatingBase = arguments.getInt(ReviewActivity.EXTRA_RATING_BASE);
mUrl = arguments.getString(ReviewActivity.EXTRA_RATING_URL);
}
@Override
public void onItemClick(View v, int position)
{
if (mUrl == null)
return;
final Intent intent = new Intent(Intent.ACTION_VIEW);
String url = mUrl;
if (!url.startsWith("http://") && !url.startsWith("https://"))
url = "http://" + url;
intent.setData(Uri.parse(url));
getContext().startActivity(intent);
}
}

View file

@ -0,0 +1,56 @@
package com.mapswithme.maps.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.text.Layout;
import android.util.AttributeSet;
import android.widget.TextView;
public class LineCountTextView extends TextView
{
public interface OnLineCountCalculatedListener
{
void onLineCountCalculated(boolean grater);
}
private OnLineCountCalculatedListener mListener;
public LineCountTextView(Context context)
{
super(context);
}
public LineCountTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public LineCountTextView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Layout layout = getLayout();
if (layout != null)
{
int textHeight = layout.getHeight();
int viewHeight = getHeight();
if (mListener != null)
{
mListener.onLineCountCalculated(textHeight > viewHeight);
}
}
}
public void setListener(OnLineCountCalculatedListener listener)
{
mListener = listener;
}
}

View file

@ -0,0 +1,30 @@
package com.mapswithme.maps.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.GridView;
public class StaticGridView extends GridView
{
public StaticGridView(Context context)
{
super(context);
}
public StaticGridView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public StaticGridView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST));
getLayoutParams().height = getMeasuredHeight();
}
}

View file

@ -0,0 +1,97 @@
package com.mapswithme.maps.widget.placepage;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.mapswithme.maps.R;
import java.util.ArrayList;
import java.util.List;
class FacilitiesAdapter extends BaseAdapter
{
static final int MAX_COUNT = 6;
@NonNull
private List<SponsoredHotel.FacilityType> mItems = new ArrayList<>();
private boolean isShowAll = false;
@Override
public int getCount()
{
if (mItems.size() > MAX_COUNT && !isShowAll)
{
return MAX_COUNT;
}
return mItems.size();
}
@Override
public Object getItem(int position)
{
return mItems.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if (convertView == null)
{
convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_facility, parent, false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.bind(mItems.get(position));
return convertView;
}
public void setItems(@NonNull List<SponsoredHotel.FacilityType> items)
{
this.mItems = items;
notifyDataSetChanged();
}
void setShowAll(boolean showAll)
{
isShowAll = showAll;
notifyDataSetChanged();
}
private static class ViewHolder
{
ImageView mIcon;
TextView mName;
public ViewHolder(View view)
{
mIcon = (ImageView) view.findViewById(R.id.iv__icon);
mName = (TextView) view.findViewById(R.id.tv__facility);
}
public void bind(SponsoredHotel.FacilityType facility)
{
// TODO map facility key to image resource id
mIcon.setImageResource(R.drawable.ic_entrance);
mName.setText(facility.getName());
}
}
}

View file

@ -0,0 +1,205 @@
package com.mapswithme.maps.widget.placepage;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.mapswithme.maps.R;
import com.mapswithme.maps.gallery.Image;
import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
import com.mapswithme.util.UiUtils;
import java.util.ArrayList;
import java.util.List;
class GalleryAdapter extends RecyclerView.Adapter<GalleryAdapter.ViewHolder>
{
static final int MAX_COUNT = 5;
private final Context mContext;
@NonNull
private ArrayList<Image> mItems = new ArrayList<>();
@NonNull
private final List<Item> mLoadedItems = new ArrayList<>();
@NonNull
private final List<Item> mItemsToDownload = new ArrayList<>();
@Nullable
private RecyclerClickListener mListener;
private final int mImageWidth;
private final int mImageHeight;
GalleryAdapter(Context context)
{
mContext = context;
mImageWidth = (int) context.getResources().getDimension(R.dimen.placepage_hotel_gallery_width);
mImageHeight = (int) context.getResources()
.getDimension(R.dimen.placepage_hotel_gallery_height);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
return new ViewHolder(LayoutInflater.from(mContext)
.inflate(R.layout.item_gallery, parent, false), mListener);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
Item item = mLoadedItems.get(position);
item.setShowMore(position == MAX_COUNT - 1 && mItems.size() > MAX_COUNT);
holder.bind(item, position);
}
@Override
public int getItemCount()
{
return mLoadedItems.size();
}
@NonNull
public ArrayList<Image> getItems()
{
return mItems;
}
public void setItems(@NonNull ArrayList<Image> items)
{
mItems = items;
for (Item item : mItemsToDownload)
{
item.setCanceled(true);
}
mItemsToDownload.clear();
mLoadedItems.clear();
loadImages();
notifyDataSetChanged();
}
public void setListener(@Nullable RecyclerClickListener listener)
{
mListener = listener;
}
private void loadImages()
{
int size = Math.min(mItems.size(), MAX_COUNT);
for (int i = 0; i < size; i++)
{
final Item item = new Item(null);
mItemsToDownload.add(item);
Image image = mItems.get(i);
Glide.with(mContext)
.load(image.getSmallUrl())
.asBitmap()
.centerCrop()
.into(new SimpleTarget<Bitmap>(mImageWidth, mImageHeight)
{
@Override
public void onResourceReady(Bitmap resource,
GlideAnimation<? super Bitmap> glideAnimation)
{
if (item.isCanceled())
return;
item.setBitmap(resource);
int size = mLoadedItems.size();
mLoadedItems.add(item);
notifyItemInserted(size);
}
});
}
}
static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
@NonNull
private ImageView mImage;
@NonNull
private View mMore;
@Nullable
private final RecyclerClickListener mListener;
private int mPosition;
public ViewHolder(View itemView, @Nullable RecyclerClickListener listener)
{
super(itemView);
mListener = listener;
mImage = (ImageView) itemView.findViewById(R.id.iv__image);
mMore = itemView.findViewById(R.id.tv__more);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v)
{
if (mListener == null)
return;
mListener.onItemClick(v, mPosition);
}
public void bind(Item item, int position)
{
mPosition = position;
mImage.setImageBitmap(item.getBitmap());
UiUtils.showIf(item.isShowMore(), mMore);
}
}
static class Item
{
@Nullable
private Bitmap mBitmap;
private boolean isShowMore;
private boolean isCanceled = false;
Item(@Nullable Bitmap bitmap)
{
this.mBitmap = bitmap;
}
@Nullable
Bitmap getBitmap()
{
return mBitmap;
}
void setBitmap(@Nullable Bitmap bitmap)
{
mBitmap = bitmap;
}
void setShowMore(boolean showMore)
{
isShowMore = showMore;
}
boolean isShowMore()
{
return isShowMore;
}
boolean isCanceled()
{
return isCanceled;
}
void setCanceled(boolean canceled)
{
isCanceled = canceled;
}
}
}

View file

@ -13,7 +13,7 @@ import com.mapswithme.util.UiUtils;
class LeftPlacePageAnimationController extends BasePlacePageAnimationController
{
public LeftPlacePageAnimationController(@NonNull PlacePageView placePage)
LeftPlacePageAnimationController(@NonNull PlacePageView placePage)
{
super(placePage);
}
@ -27,18 +27,21 @@ class LeftPlacePageAnimationController extends BasePlacePageAnimationController
@Override
protected boolean onInterceptTouchEvent(MotionEvent event)
{
if (mPlacePage.isTouchGallery(event))
return false;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
mIsDragging = false;
mDownCoord = event.getX();
break;
case MotionEvent.ACTION_MOVE:
if (mDownCoord > mPlacePage.getRight())
return false;
if (Math.abs(mDownCoord - event.getX()) > mTouchSlop)
return true;
break;
case MotionEvent.ACTION_DOWN:
mIsDragging = false;
mDownCoord = event.getX();
break;
case MotionEvent.ACTION_MOVE:
if (mDownCoord > mPlacePage.getRight())
return false;
if (Math.abs(mDownCoord - event.getX()) > mTouchSlop)
return true;
break;
}
return false;
@ -70,7 +73,7 @@ class LeftPlacePageAnimationController extends BasePlacePageAnimationController
final boolean isInRange = Math.abs(distanceX) > X_MIN && Math.abs(distanceX) < X_MAX;
if (!isHorizontal || !isInRange)
return false;;
return false;
if (!mIsDragging)
{
@ -90,13 +93,13 @@ class LeftPlacePageAnimationController extends BasePlacePageAnimationController
{
switch (newState)
{
case HIDDEN:
hidePlacePage();
break;
case DETAILS:
case PREVIEW:
showPlacePage(currentState, newState);
break;
case HIDDEN:
hidePlacePage();
break;
case DETAILS:
case PREVIEW:
showPlacePage(currentState);
break;
}
}
@ -130,7 +133,7 @@ class LeftPlacePageAnimationController extends BasePlacePageAnimationController
tracker.onTrackLeftAnimation(offset + mPlacePage.getDockedWidth());
}
private void showPlacePage(final State currentState, final State newState)
private void showPlacePage(final State currentState)
{
UiUtils.show(mPlacePage);
if (currentState != State.HIDDEN)

View file

@ -0,0 +1,134 @@
package com.mapswithme.maps.widget.placepage;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.mapswithme.maps.R;
import com.mapswithme.util.ThemeUtils;
import java.util.ArrayList;
import java.util.List;
class NearbyAdapter extends BaseAdapter
{
@NonNull
private List<SponsoredHotel.NearbyObject> mItems = new ArrayList<>();
@Nullable
private final OnItemClickListener mListener;
NearbyAdapter(@Nullable OnItemClickListener listener)
{
mListener = listener;
}
interface OnItemClickListener
{
void onItemClick(@NonNull SponsoredHotel.NearbyObject item);
}
@Override
public int getCount()
{
return mItems.size();
}
@Override
public Object getItem(int position)
{
return mItems.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if (convertView == null)
{
convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_nearby, parent, false);
holder = new ViewHolder(convertView, mListener);
convertView.setTag(holder);
} else
{
holder = (ViewHolder) convertView.getTag();
}
holder.bind(mItems.get(position));
return convertView;
}
public void setItems(@NonNull List<SponsoredHotel.NearbyObject> items)
{
this.mItems = items;
notifyDataSetChanged();
}
private static class ViewHolder implements View.OnClickListener
{
@Nullable
final OnItemClickListener mListener;
@NonNull
ImageView mIcon;
@NonNull
TextView mTitle;
@NonNull
TextView mType;
@NonNull
TextView mDistance;
@Nullable
SponsoredHotel.NearbyObject mItem;
public ViewHolder(View view, @Nullable OnItemClickListener listener)
{
mListener = listener;
mIcon = (ImageView) view.findViewById(R.id.iv__icon);
mTitle = (TextView) view.findViewById(R.id.tv__title);
mType = (TextView) view.findViewById(R.id.tv__type);
mDistance = (TextView) view.findViewById(R.id.tv__distance);
view.setOnClickListener(this);
}
@Override
public void onClick(View v)
{
if (mListener != null && mItem != null)
mListener.onItemClick(mItem);
}
public void bind(@NonNull SponsoredHotel.NearbyObject item)
{
mItem = item;
String packageName = mType.getContext().getPackageName();
final boolean isNightTheme = ThemeUtils.isNightTheme();
Resources resources = mType.getResources();
int categoryRes = resources.getIdentifier(item.getCategory(), "string", packageName);
if (categoryRes == 0)
throw new IllegalStateException("Can't get string resource id for category:" + item.getCategory());
String iconId = "ic_category_" + item.getCategory();
if (isNightTheme)
iconId = iconId + "_night";
int iconRes = resources.getIdentifier(iconId, "drawable", packageName);
if (iconRes == 0)
throw new IllegalStateException("Can't get icon resource id:" + iconId);
mIcon.setImageResource(iconRes);
mTitle.setText(item.getTitle());
mType.setText(categoryRes);
mDistance.setText(item.getDistance());
}
}
}

View file

@ -12,6 +12,9 @@ import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@ -24,6 +27,7 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
@ -31,15 +35,6 @@ import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Currency;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import com.mapswithme.maps.Framework;
import com.mapswithme.maps.MwmActivity;
import com.mapswithme.maps.MwmApplication;
@ -57,12 +52,18 @@ import com.mapswithme.maps.editor.Editor;
import com.mapswithme.maps.editor.OpeningHours;
import com.mapswithme.maps.editor.data.TimeFormatUtils;
import com.mapswithme.maps.editor.data.Timetable;
import com.mapswithme.maps.gallery.FullScreenGalleryActivity;
import com.mapswithme.maps.gallery.GalleryActivity;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.maps.review.ReviewActivity;
import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.maps.widget.ArrowView;
import com.mapswithme.maps.widget.BaseShadowController;
import com.mapswithme.maps.widget.LineCountTextView;
import com.mapswithme.maps.widget.ObservableScrollView;
import com.mapswithme.maps.widget.ScrollViewShadowController;
import com.mapswithme.maps.widget.recycler.DividerItemDecoration;
import com.mapswithme.maps.widget.recycler.RecyclerClickListener;
import com.mapswithme.util.Graphics;
import com.mapswithme.util.StringUtils;
import com.mapswithme.util.ThemeUtils;
@ -73,14 +74,30 @@ import com.mapswithme.util.sharing.ShareOption;
import com.mapswithme.util.statistics.AlohaHelper;
import com.mapswithme.util.statistics.Statistics;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Currency;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class PlacePageView extends RelativeLayout
implements View.OnClickListener,
View.OnLongClickListener,
SponsoredHotel.OnPriceReceivedListener
implements View.OnClickListener,
View.OnLongClickListener,
SponsoredHotel.OnPriceReceivedListener,
SponsoredHotel.OnInfoReceivedListener,
LineCountTextView.OnLineCountCalculatedListener,
RecyclerClickListener,
NearbyAdapter.OnItemClickListener
{
private static final String PREF_USE_DMS = "use_dms";
//TODO: remove this after booking_api.cpp will be done
private static final boolean USE_OLD_BOOKING = true;
private boolean mIsDocked;
private boolean mIsFloating;
@ -118,7 +135,6 @@ public class PlacePageView extends RelativeLayout
private View mEditPlace;
private View mAddOrganisation;
private View mAddPlace;
private View mMoreInfo;
// Bookmark
private View mBookmarkFrame;
private TextView mBookmarkNote;
@ -126,6 +142,20 @@ public class PlacePageView extends RelativeLayout
// Place page buttons
private PlacePageButtons mButtons;
private ImageView mBookmarkButtonIcon;
// Hotel
private View mHotelDescription;
private LineCountTextView mTvHotelDescription;
private View mHotelMoreDescription;
private View mHotelFacilities;
private View mHotelMoreFacilities;
private View mHotelGallery;
private RecyclerView mRvHotelGallery;
private View mHotelNearby;
private View mHotelReview;
private TextView mHotelRating;
private TextView mHotelRatingBase;
//TODO: remove this after booking_api.cpp will be done
private View mHotelMore;
// Animations
private BaseShadowController mShadowController;
@ -136,6 +166,14 @@ public class PlacePageView extends RelativeLayout
private SponsoredHotel mSponsoredHotel;
private String mSponsoredHotelPrice;
private boolean mIsLatLonDms;
@NonNull
private final FacilitiesAdapter mFacilitiesAdapter = new FacilitiesAdapter();
@NonNull
private final GalleryAdapter mGalleryAdapter;
@NonNull
private final NearbyAdapter mNearbyAdapter = new NearbyAdapter(this);
@NonNull
private final ReviewAdapter mReviewAdapter = new ReviewAdapter();
// Downloader`s stuff
private DownloaderStatusIcon mDownloaderIcon;
@ -198,12 +236,17 @@ public class PlacePageView extends RelativeLayout
super(context, attrs);
mIsLatLonDms = MwmApplication.prefs().getBoolean(PREF_USE_DMS, false);
mGalleryAdapter = new GalleryAdapter(context);
init(attrs, defStyleAttr);
}
public ViewGroup GetPreview() { return mPreview; }
public boolean isTouchGallery(@NonNull MotionEvent event)
{
return UiUtils.isViewTouched(event, mHotelGallery);
}
private void initViews()
{
LayoutInflater.from(getContext()).inflate(R.layout.place_page, this);
@ -257,8 +300,6 @@ public class PlacePageView extends RelativeLayout
mAddOrganisation.setOnClickListener(this);
mAddPlace = mDetails.findViewById(R.id.ll__place_add);
mAddPlace.setOnClickListener(this);
mMoreInfo = mDetails.findViewById(R.id.ll__more);
mMoreInfo.setOnClickListener(this);
latlon.setOnLongClickListener(this);
address.setOnLongClickListener(this);
mPhone.setOnLongClickListener(this);
@ -274,6 +315,16 @@ public class PlacePageView extends RelativeLayout
ViewGroup ppButtons = (ViewGroup) findViewById(R.id.pp__buttons);
// TODO: remove this after booking_api.cpp will be done
mHotelMore = findViewById(R.id.ll__more);
mHotelMore.setOnClickListener(this);
initHotelDescriptionView();
initHotelFacilitiesView();
initHotelGalleryView();
initHotelNearbyView();
initHotelRatingView();
mButtons = new PlacePageButtons(this, ppButtons, new PlacePageButtons.ItemListener()
{
@Override
@ -283,21 +334,21 @@ public class PlacePageView extends RelativeLayout
switch (item)
{
case BOOKING:
frame.setBackgroundResource(R.drawable.button_booking);
color = Color.WHITE;
break;
case BOOKING:
frame.setBackgroundResource(R.drawable.button_booking);
color = Color.WHITE;
break;
case BOOKMARK:
mBookmarkButtonIcon = icon;
updateButtons();
color = ThemeUtils.getColor(getContext(), R.attr.iconTint);
break;
case BOOKMARK:
mBookmarkButtonIcon = icon;
updateButtons();
color = ThemeUtils.getColor(getContext(), R.attr.iconTint);
break;
default:
color = ThemeUtils.getColor(getContext(), R.attr.iconTint);
icon.setColorFilter(color);
break;
default:
color = ThemeUtils.getColor(getContext(), R.attr.iconTint);
icon.setColorFilter(color);
break;
}
title.setTextColor(color);
@ -338,62 +389,63 @@ public class PlacePageView extends RelativeLayout
hide();
break;
case ROUTE_TO:
if (RoutingController.get().isPlanning())
{
if (RoutingController.get().setEndPoint(mMapObject))
hide();
}
else
{
getActivity().startLocationToPoint(Statistics.EventName.PP_ROUTE, AlohaHelper.PP_ROUTE, getMapObject());
}
break;
case ROUTE_TO:
if (RoutingController.get().isPlanning())
{
if (RoutingController.get().setEndPoint(mMapObject))
hide();
}
else
{
getActivity().startLocationToPoint(Statistics.EventName.PP_ROUTE, AlohaHelper.PP_ROUTE, getMapObject());
}
break;
case BOOKING:
onBookingClick(true /* book */);
break;
case BOOKING:
onBookingClick(true /* book */);
break;
}
}
});
mDownloaderIcon = new DownloaderStatusIcon(mPreview.findViewById(R.id.downloader_status_frame))
.setOnIconClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
MapManager.warn3gAndDownload(getActivity(), mCurrentCountry.id, new Runnable()
{
@Override
public void run()
{
Statistics.INSTANCE.trackEvent(Statistics.EventName.DOWNLOADER_ACTION,
Statistics.params()
.add(Statistics.EventParam.ACTION, "download")
.add(Statistics.EventParam.FROM, "placepage")
.add("is_auto", "false")
.add("scenario", (mCurrentCountry.isExpandable() ? "download_group"
: "download")));
}
});
}
}).setOnCancelClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
MapManager.nativeCancel(mCurrentCountry.id);
Statistics.INSTANCE.trackEvent(Statistics.EventName.DOWNLOADER_CANCEL,
Statistics.params().add(Statistics.EventParam.FROM, "placepage"));
}
});
.setOnIconClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
MapManager.warn3gAndDownload(getActivity(), mCurrentCountry.id, new Runnable()
{
@Override
public void run()
{
Statistics.INSTANCE.trackEvent(Statistics.EventName.DOWNLOADER_ACTION,
Statistics.params()
.add(Statistics.EventParam.ACTION, "download")
.add(Statistics.EventParam.FROM, "placepage")
.add("is_auto", "false")
.add("scenario", (mCurrentCountry.isExpandable() ? "download_group"
: "download")));
}
});
}
}).setOnCancelClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
MapManager.nativeCancel(mCurrentCountry.id);
Statistics.INSTANCE.trackEvent(Statistics.EventName.DOWNLOADER_CANCEL,
Statistics.params()
.add(Statistics.EventParam.FROM, "placepage"));
}
});
mDownloaderInfo = (TextView) mPreview.findViewById(R.id.tv__downloader_details);
mShadowController = new ScrollViewShadowController((ObservableScrollView) mDetails)
.addBottomShadow()
.attach();
.addBottomShadow()
.attach();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
setElevation(UiUtils.dimen(R.dimen.placepage_elevation));
@ -401,11 +453,62 @@ public class PlacePageView extends RelativeLayout
if (UiUtils.isLandscape(getContext()))
mDetails.setBackgroundResource(0);
SponsoredHotel.setListener(this);
SponsoredHotel.setPriceListener(this);
SponsoredHotel.setInfoListener(this);
}
private void initHotelRatingView()
{
mHotelReview = findViewById(R.id.ll__place_hotel_rating);
GridView gvHotelReview = (GridView) findViewById(R.id.gv__place_hotel_review);
gvHotelReview.setAdapter(mReviewAdapter);
mHotelRating = (TextView) findViewById(R.id.tv__place_hotel_rating);
mHotelRatingBase = (TextView) findViewById(R.id.tv__place_hotel_rating_base);
View hotelMoreReviews = findViewById(R.id.tv__place_hotel_reviews_more);
hotelMoreReviews.setOnClickListener(this);
}
private void initHotelNearbyView()
{
mHotelNearby = findViewById(R.id.ll__place_hotel_nearby);
GridView gvHotelNearby = (GridView) findViewById(R.id.gv__place_hotel_nearby);
gvHotelNearby.setAdapter(mNearbyAdapter);
}
private void initHotelGalleryView()
{
mHotelGallery = findViewById(R.id.ll__place_hotel_gallery);
mRvHotelGallery = (RecyclerView) findViewById(
R.id.rv__place_hotel_gallery);
mRvHotelGallery.setLayoutManager(new LinearLayoutManager(getContext(),
LinearLayoutManager.HORIZONTAL, false));
mRvHotelGallery.addItemDecoration(new DividerItemDecoration(ContextCompat.getDrawable(getContext(),
R.drawable.divider_transparent)));
mGalleryAdapter.setListener(this);
mRvHotelGallery.setAdapter(mGalleryAdapter);
}
private void initHotelFacilitiesView()
{
mHotelFacilities = findViewById(R.id.ll__place_hotel_facilities);
GridView gvHotelFacilities = (GridView) findViewById(R.id.gv__place_hotel_facilities);
mHotelMoreFacilities = findViewById(R.id.tv__place_hotel_facilities_more);
gvHotelFacilities.setAdapter(mFacilitiesAdapter);
mHotelMoreFacilities.setOnClickListener(this);
}
private void initHotelDescriptionView()
{
mHotelDescription = findViewById(R.id.ll__place_hotel_description);
mTvHotelDescription = (LineCountTextView) findViewById(R.id.tv__place_hotel_details);
mHotelMoreDescription = findViewById(R.id.tv__place_hotel_more);
mTvHotelDescription.setListener(this);
mHotelMoreDescription.setOnClickListener(this);
}
@Override
public void onPriceReceived(String id, String price, String currencyCode)
public void onPriceReceived(@NonNull String id, @NonNull String price,
@NonNull String currencyCode)
{
if (mSponsoredHotel == null || !TextUtils.equals(id, mSponsoredHotel.getId()))
return;
@ -424,6 +527,110 @@ public class PlacePageView extends RelativeLayout
refreshPreview();
}
@Override
public void onInfoReceived(@NonNull String id, @NonNull SponsoredHotel.HotelInfo info)
{
if (mSponsoredHotel == null || !TextUtils.equals(id, mSponsoredHotel.getId()))
return;
updateHotelDetails(info);
updateHotelFacilities(info);
updateHotelGallery(info);
updateHotelNearby(info);
updateHotelRating(info);
}
private void updateHotelRating(@NonNull SponsoredHotel.HotelInfo info)
{
if (info.mReviews == null || info.mReviews.length == 0)
{
UiUtils.hide(mHotelReview);
}
else
{
UiUtils.show(mHotelReview);
mReviewAdapter.setItems(new ArrayList<>(Arrays.asList(info.mReviews)));
mHotelRating.setText(mSponsoredHotel.mRating);
mHotelRatingBase.setText(getResources().getQuantityString(R.plurals.place_page_booking_rating_base,
info.mReviews.length, info.mReviews.length));
}
}
private void updateHotelNearby(@NonNull SponsoredHotel.HotelInfo info)
{
if (info.mNearby == null || info.mNearby.length == 0)
{
UiUtils.hide(mHotelNearby);
}
else
{
UiUtils.show(mHotelNearby);
mNearbyAdapter.setItems(Arrays.asList(info.mNearby));
}
}
private void updateHotelGallery(@NonNull SponsoredHotel.HotelInfo info)
{
if (info.mPhotos == null || info.mPhotos.length == 0)
{
UiUtils.hide(mHotelGallery);
}
else
{
UiUtils.show(mHotelGallery);
mGalleryAdapter.setItems(new ArrayList<>(Arrays.asList(info.mPhotos)));
mRvHotelGallery.scrollToPosition(0);
}
}
private void updateHotelFacilities(@NonNull SponsoredHotel.HotelInfo info)
{
if (info.mFacilities == null || info.mFacilities.length == 0)
{
UiUtils.hide(mHotelFacilities);
}
else
{
UiUtils.show(mHotelFacilities);
mFacilitiesAdapter.setShowAll(false);
mFacilitiesAdapter.setItems(Arrays.asList(info.mFacilities));
mHotelMoreFacilities.setVisibility(info.mFacilities.length > FacilitiesAdapter.MAX_COUNT
? VISIBLE : GONE);
}
}
private void updateHotelDetails(@NonNull SponsoredHotel.HotelInfo info)
{
mTvHotelDescription.setMaxLines(getResources().getInteger(R.integer.pp_hotel_description_lines));
refreshMetadataOrHide(info.mDescription, mHotelDescription, mTvHotelDescription);
mHotelMoreDescription.setVisibility(GONE);
}
@Override
public void onLineCountCalculated(boolean grater)
{
UiUtils.showIf(grater, mHotelMoreDescription);
}
@Override
public void onItemClick(View v, int position)
{
if (position == GalleryAdapter.MAX_COUNT - 1)
{
GalleryActivity.start(getContext(), mGalleryAdapter.getItems(), mMapObject.getTitle());
}
else
{
FullScreenGalleryActivity.start(getContext(), mGalleryAdapter.getItems(), position);
}
}
@Override
public void onItemClick(@NonNull SponsoredHotel.NearbyObject item)
{
// TODO go to selected object on map
}
private void onBookingClick(final boolean book)
{
// TODO (trashkalmar): Set correct text
@ -453,7 +660,7 @@ public class PlacePageView extends RelativeLayout
try
{
followUrl(book ? info.urlBook : info.urlDescription);
followUrl(book ? info.mUrlBook : info.mUrlDescription);
} catch (ActivityNotFoundException e)
{
AlohaHelper.logException(e);
@ -482,7 +689,7 @@ public class PlacePageView extends RelativeLayout
public void restore()
{
// if (mMapObject != null)
// FIXME query map object again
// FIXME query map object again
}
@Override
@ -539,7 +746,7 @@ public class PlacePageView extends RelativeLayout
/**
* @param mapObject new MapObject
* @param force if true, new object'll be set without comparison with the old one
* @param force if true, new object'll be set without comparison with the old one
*/
public void setMapObject(MapObject mapObject, boolean force)
{
@ -555,10 +762,14 @@ public class PlacePageView extends RelativeLayout
if (mSponsoredHotel != null)
{
mSponsoredHotel.updateId(mMapObject);
mSponsoredHotelPrice = mSponsoredHotel.price;
mSponsoredHotelPrice = mSponsoredHotel.mPrice;
Currency currency = Currency.getInstance(Locale.getDefault());
Locale locale = Locale.getDefault();
Currency currency = Currency.getInstance(locale);
SponsoredHotel.requestPrice(mSponsoredHotel.getId(), currency.getCurrencyCode());
// TODO: remove this after booking_api.cpp will be done
if (!USE_OLD_BOOKING)
SponsoredHotel.requestInfo(mSponsoredHotel.getId(), locale.toString());
}
String country = MapManager.nativeGetSelectedCountry();
@ -580,27 +791,27 @@ public class PlacePageView extends RelativeLayout
switch (mMapObject.getMapObjectType())
{
case MapObject.BOOKMARK:
refreshDistanceToObject(loc);
showBookmarkDetails();
setButtons(false, true);
break;
case MapObject.POI:
case MapObject.SEARCH:
refreshDistanceToObject(loc);
hideBookmarkDetails();
setButtons(false, true);
break;
case MapObject.API_POINT:
refreshDistanceToObject(loc);
hideBookmarkDetails();
setButtons(true, true);
break;
case MapObject.MY_POSITION:
refreshMyPosition(loc);
hideBookmarkDetails();
setButtons(false, false);
break;
case MapObject.BOOKMARK:
refreshDistanceToObject(loc);
showBookmarkDetails();
setButtons(false, true);
break;
case MapObject.POI:
case MapObject.SEARCH:
refreshDistanceToObject(loc);
hideBookmarkDetails();
setButtons(false, true);
break;
case MapObject.API_POINT:
refreshDistanceToObject(loc);
hideBookmarkDetails();
setButtons(true, true);
break;
case MapObject.MY_POSITION:
refreshMyPosition(loc);
hideBookmarkDetails();
setButtons(false, false);
break;
}
UiThread.runLater(new Runnable()
@ -645,7 +856,7 @@ public class PlacePageView extends RelativeLayout
UiUtils.showIf(sponsored, mHotelInfo);
if (sponsored)
{
mTvHotelRating.setText(mSponsoredHotel.rating);
mTvHotelRating.setText(mSponsoredHotel.mRating);
UiUtils.setTextAndHideIfEmpty(mTvHotelPrice, mSponsoredHotelPrice);
}
}
@ -658,9 +869,21 @@ public class PlacePageView extends RelativeLayout
{
final String website = mMapObject.getMetadata(Metadata.MetadataType.FMD_WEBSITE);
refreshMetadataOrHide(TextUtils.isEmpty(website) ? mMapObject.getMetadata(Metadata.MetadataType.FMD_URL) : website, mWebsite, mTvWebsite);
UiUtils.hide(mHotelDescription);
UiUtils.hide(mHotelFacilities);
UiUtils.hide(mHotelGallery);
UiUtils.hide(mHotelNearby);
UiUtils.hide(mHotelReview);
// TODO: remove this after booking_api.cpp will be done
UiUtils.hide(mHotelMore);
}
else
{
UiUtils.hide(mWebsite);
// TODO: remove this after booking_api.cpp will be done
if (!USE_OLD_BOOKING)
UiUtils.hide(mHotelMore);
}
refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_PHONE_NUMBER), mPhone, mTvPhone);
refreshMetadataOrHide(mMapObject.getMetadata(Metadata.MetadataType.FMD_EMAIL), mEmail, mTvEmail);
@ -683,8 +906,6 @@ public class PlacePageView extends RelativeLayout
UiUtils.showIf(Editor.nativeShouldShowAddBusiness(), mAddOrganisation);
UiUtils.showIf(Editor.nativeShouldShowAddPlace(), mAddPlace);
}
UiUtils.showIf(mSponsoredHotel != null, mMoreInfo);
}
private void refreshOpeningHours()
@ -824,8 +1045,11 @@ public class PlacePageView extends RelativeLayout
return;
mTvDistance.setVisibility(View.VISIBLE);
DistanceAndAzimut distanceAndAzimuth = Framework.nativeGetDistanceAndAzimuthFromLatLon(mMapObject.getLat(), mMapObject.getLon(),
l.getLatitude(), l.getLongitude(), 0.0);
DistanceAndAzimut distanceAndAzimuth = Framework.nativeGetDistanceAndAzimuthFromLatLon(mMapObject
.getLat(), mMapObject
.getLon(),
l.getLatitude(), l
.getLongitude(), 0.0);
mTvDistance.setText(distanceAndAzimuth.getDistance());
}
@ -853,16 +1077,18 @@ public class PlacePageView extends RelativeLayout
public void refreshAzimuth(double northAzimuth)
{
if (isHidden() ||
mMapObject == null ||
MapObject.isOfType(MapObject.MY_POSITION, mMapObject))
mMapObject == null ||
MapObject.isOfType(MapObject.MY_POSITION, mMapObject))
return;
final Location location = LocationHelper.INSTANCE.getSavedLocation();
if (location == null)
return;
final double azimuth = Framework.nativeGetDistanceAndAzimuthFromLatLon(mMapObject.getLat(), mMapObject.getLon(),
location.getLatitude(), location.getLongitude(),
final double azimuth = Framework.nativeGetDistanceAndAzimuthFromLatLon(mMapObject.getLat(), mMapObject
.getLon(),
location.getLatitude(), location
.getLongitude(),
northAzimuth)
.getAzimuth();
if (azimuth >= 0)
@ -880,7 +1106,8 @@ public class PlacePageView extends RelativeLayout
private void addOrganisation()
{
Statistics.INSTANCE.trackEvent(Statistics.EventName.EDITOR_ADD_CLICK,
Statistics.params().add(Statistics.EventParam.FROM, "placepage"));
Statistics.params()
.add(Statistics.EventParam.FROM, "placepage"));
getActivity().showPositionChooser(true, false);
}
@ -895,56 +1122,69 @@ public class PlacePageView extends RelativeLayout
{
switch (v.getId())
{
case R.id.ll__place_editor:
getActivity().showEditor();
break;
case R.id.ll__add_organisation:
addOrganisation();
break;
case R.id.ll__place_add:
addPlace();
break;
case R.id.ll__more:
onBookingClick(false /* book */);
break;
case R.id.ll__place_latlon:
mIsLatLonDms = !mIsLatLonDms;
MwmApplication.prefs().edit().putBoolean(PREF_USE_DMS, mIsLatLonDms).commit();
refreshLatLon();
break;
case R.id.ll__place_phone:
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + mTvPhone.getText()));
try
{
case R.id.ll__place_editor:
getActivity().showEditor();
break;
case R.id.ll__add_organisation:
addOrganisation();
break;
case R.id.ll__place_add:
addPlace();
break;
case R.id.ll__more:
onBookingClick(false /* book */);
break;
case R.id.ll__place_latlon:
mIsLatLonDms = !mIsLatLonDms;
MwmApplication.prefs().edit().putBoolean(PREF_USE_DMS, mIsLatLonDms).commit();
refreshLatLon();
break;
case R.id.ll__place_phone:
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + mTvPhone.getText()));
try
{
getContext().startActivity(intent);
} catch (ActivityNotFoundException e)
{
AlohaHelper.logException(e);
}
break;
case R.id.ll__place_website:
followUrl(mTvWebsite.getText().toString());
break;
case R.id.ll__place_wiki:
// TODO: Refactor and use separate getters for Wiki and all other PP meta info too.
followUrl(mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA));
break;
case R.id.direction_frame:
Statistics.INSTANCE.trackEvent(Statistics.EventName.PP_DIRECTION_ARROW);
AlohaHelper.logClick(AlohaHelper.PP_DIRECTION_ARROW);
showBigDirection();
break;
case R.id.ll__place_email:
intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Utils.buildMailUri(mTvEmail.getText().toString(), "", ""));
getContext().startActivity(intent);
} catch (ActivityNotFoundException e)
{
AlohaHelper.logException(e);
}
break;
case R.id.ll__place_website:
followUrl(mTvWebsite.getText().toString());
break;
case R.id.ll__place_wiki:
// TODO: Refactor and use separate getters for Wiki and all other PP meta info too.
followUrl(mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA));
break;
case R.id.direction_frame:
Statistics.INSTANCE.trackEvent(Statistics.EventName.PP_DIRECTION_ARROW);
AlohaHelper.logClick(AlohaHelper.PP_DIRECTION_ARROW);
showBigDirection();
break;
case R.id.ll__place_email:
intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Utils.buildMailUri(mTvEmail.getText().toString(), "", ""));
getContext().startActivity(intent);
break;
case R.id.tv__bookmark_edit:
Bookmark bookmark = (Bookmark) mMapObject;
EditBookmarkFragment.editBookmark(bookmark.getCategoryId(), bookmark.getBookmarkId(),
getActivity(), getActivity().getSupportFragmentManager());
break;
break;
case R.id.tv__bookmark_edit:
Bookmark bookmark = (Bookmark) mMapObject;
EditBookmarkFragment.editBookmark(bookmark.getCategoryId(), bookmark.getBookmarkId(),
getActivity(), getActivity().getSupportFragmentManager());
break;
case R.id.tv__place_hotel_more:
UiUtils.hide(mHotelMoreDescription);
mTvHotelDescription.setMaxLines(Integer.MAX_VALUE);
break;
case R.id.tv__place_hotel_facilities_more:
UiUtils.hide(mHotelMoreFacilities);
mFacilitiesAdapter.setShowAll(true);
break;
case R.id.tv__place_hotel_reviews_more:
ReviewActivity.start(getContext(), mReviewAdapter.getItems(), mMapObject.getTitle(),
mSponsoredHotel.mRating, mReviewAdapter.getItems()
.size(), mSponsoredHotel.mUrlBook);
break;
}
}
@ -976,7 +1216,8 @@ public class PlacePageView extends RelativeLayout
private void showBigDirection()
{
final DirectionFragment fragment = (DirectionFragment) Fragment.instantiate(getActivity(), DirectionFragment.class.getName(), null);
final DirectionFragment fragment = (DirectionFragment) Fragment.instantiate(getActivity(), DirectionFragment.class
.getName(), null);
fragment.setMapObject(mMapObject);
fragment.show(getActivity().getSupportFragmentManager(), null);
}
@ -993,30 +1234,30 @@ public class PlacePageView extends RelativeLayout
final List<String> items = new ArrayList<>();
switch (v.getId())
{
case R.id.ll__place_latlon:
final double lat = mMapObject.getLat();
final double lon = mMapObject.getLon();
items.add(Framework.nativeFormatLatLon(lat, lon, false));
items.add(Framework.nativeFormatLatLon(lat, lon, true));
break;
case R.id.ll__place_website:
items.add(mTvWebsite.getText().toString());
break;
case R.id.ll__place_email:
items.add(mTvEmail.getText().toString());
break;
case R.id.ll__place_phone:
items.add(mTvPhone.getText().toString());
break;
case R.id.ll__place_schedule:
items.add(mFullOpeningHours.getText().toString());
break;
case R.id.ll__place_operator:
items.add(mTvOperator.getText().toString());
break;
case R.id.ll__place_wiki:
items.add(mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA));
break;
case R.id.ll__place_latlon:
final double lat = mMapObject.getLat();
final double lon = mMapObject.getLon();
items.add(Framework.nativeFormatLatLon(lat, lon, false));
items.add(Framework.nativeFormatLatLon(lat, lon, true));
break;
case R.id.ll__place_website:
items.add(mTvWebsite.getText().toString());
break;
case R.id.ll__place_email:
items.add(mTvEmail.getText().toString());
break;
case R.id.ll__place_phone:
items.add(mTvPhone.getText().toString());
break;
case R.id.ll__place_schedule:
items.add(mFullOpeningHours.getText().toString());
break;
case R.id.ll__place_operator:
items.add(mTvOperator.getText().toString());
break;
case R.id.ll__place_wiki:
items.add(mMapObject.getMetadata(Metadata.MetadataType.FMD_WIKIPEDIA));
break;
}
final String copyText = getResources().getString(android.R.string.copy);

View file

@ -0,0 +1,136 @@
package com.mapswithme.maps.widget.placepage;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.mapswithme.maps.R;
import com.mapswithme.maps.review.Review;
import com.mapswithme.util.UiUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
class ReviewAdapter extends BaseAdapter
{
private static final int MAX_COUNT = 3;
@NonNull
private ArrayList<Review> mItems = new ArrayList<>();
@Override
public int getCount()
{
return Math.min(mItems.size(), MAX_COUNT);
}
@Override
public Object getItem(int position)
{
return mItems.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if (convertView == null)
{
convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_comment, parent, false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.bind(mItems.get(position), position > 0);
return convertView;
}
public void setItems(@NonNull ArrayList<Review> items)
{
this.mItems = items;
notifyDataSetChanged();
}
@NonNull
public ArrayList<Review> getItems()
{
return mItems;
}
private static class ViewHolder
{
@NonNull
final View mDivider;
@NonNull
final TextView mUserName;
@NonNull
final TextView mCommentDate;
@NonNull
final TextView mRating;
@NonNull
final View mPositiveReview;
@NonNull
final TextView mTvPositiveReview;
@NonNull
final View mNegativeReview;
@NonNull
final TextView mTvNegativeReview;
public ViewHolder(View view)
{
mDivider = view.findViewById(R.id.v__divider);
mUserName = (TextView) view.findViewById(R.id.tv__user_name);
mCommentDate = (TextView) view.findViewById(R.id.tv__comment_date);
mRating = (TextView) view.findViewById(R.id.tv__user_rating);
mPositiveReview = view.findViewById(R.id.ll__positive_review);
mTvPositiveReview = (TextView) view.findViewById(R.id.tv__positive_review);
mNegativeReview = view.findViewById(R.id.ll__negative_review);
mTvNegativeReview = (TextView) view.findViewById(R.id.tv__negative_review);
}
public void bind(Review item, boolean isShowDivider)
{
UiUtils.showIf(isShowDivider, mDivider);
mUserName.setText(item.getAuthor());
Date date = new Date(item.getDate());
mCommentDate.setText(DateFormat.getMediumDateFormat(mCommentDate.getContext()).format(date));
mRating.setText(String.format(Locale.getDefault(), "%.1f", item.getRating()));
if (TextUtils.isEmpty(item.getReviewPositive()))
{
UiUtils.hide(mPositiveReview);
}
else
{
UiUtils.show(mPositiveReview);
mTvPositiveReview.setText(item.getReviewPositive());
}
if (TextUtils.isEmpty(item.getReviewNegative()))
{
UiUtils.hide(mNegativeReview);
}
else
{
UiUtils.show(mNegativeReview);
mTvNegativeReview.setText(item.getReviewNegative());
}
}
}
}

View file

@ -1,53 +1,194 @@
package com.mapswithme.maps.widget.placepage;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.text.TextUtils;
import com.mapswithme.maps.bookmarks.data.MapObject;
import com.mapswithme.maps.bookmarks.data.Metadata;
import com.mapswithme.maps.gallery.Image;
import com.mapswithme.maps.review.Review;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import com.mapswithme.maps.bookmarks.data.MapObject;
import com.mapswithme.maps.bookmarks.data.Metadata;
@UiThread
public final class SponsoredHotel
{
private static class Price
{
final String price;
final String currency;
@NonNull
final String mPrice;
@NonNull
final String mCurrency;
private Price(String price, String currency)
private Price(@NonNull String price, @NonNull String currency)
{
this.price = price;
this.currency = currency;
mPrice = price;
mCurrency = currency;
}
}
static class FacilityType
{
@NonNull
private final String mKey;
@NonNull
private final String mName;
public FacilityType(@NonNull String key, @NonNull String name)
{
mKey = key;
mName = name;
}
@NonNull
public String getKey()
{
return mKey;
}
@NonNull
public String getName()
{
return mName;
}
}
static class NearbyObject
{
@NonNull
private final String mCategory;
@NonNull
private final String mTitle;
@NonNull
private final String mDistance;
private final double mLatitude;
private final double mLongitude;
public NearbyObject(@NonNull String category, @NonNull String title,
@NonNull String distance, double lat, double lon)
{
mCategory = category;
mTitle = title;
mDistance = distance;
mLatitude = lat;
mLongitude = lon;
}
@NonNull
public String getCategory()
{
return mCategory;
}
@NonNull
public String getTitle()
{
return mTitle;
}
@NonNull
public String getDistance()
{
return mDistance;
}
public double getLatitude()
{
return mLatitude;
}
public double getLongitude()
{
return mLongitude;
}
}
static class HotelInfo
{
@Nullable
final String mDescription;
@Nullable
final Image[] mPhotos;
@Nullable
final FacilityType[] mFacilities;
@Nullable
final Review[] mReviews;
@Nullable
final NearbyObject[] mNearby;
public HotelInfo(@Nullable String description, @Nullable Image[] photos,
@Nullable FacilityType[] facilities, @Nullable Review[] reviews,
@Nullable NearbyObject[] nearby)
{
mDescription = description;
mPhotos = photos;
mFacilities = facilities;
mReviews = reviews;
mNearby = nearby;
}
}
interface OnPriceReceivedListener
{
void onPriceReceived(String id, String price, String currency);
/**
* This method is called from the native core on the UI thread
* when the Hotel price will be obtained
*
* @param id A hotel id
* @param price A price
* @param currency A price currency
*/
@UiThread
void onPriceReceived(@NonNull String id, @NonNull String price, @NonNull String currency);
}
interface OnInfoReceivedListener
{
/**
* This method is called from the native core on the UI thread
* when the Hotel information will be obtained
*
* @param id A hotel id
* @param info A hotel info
*/
@UiThread
void onInfoReceived(@NonNull String id, @NonNull HotelInfo info);
}
// Hotel ID -> Price
@NonNull
private static final Map<String, Price> sPriceCache = new HashMap<>();
private static WeakReference<OnPriceReceivedListener> sListener;
// Hotel ID -> Description
@NonNull
private static final Map<String, HotelInfo> sInfoCache = new HashMap<>();
@NonNull
private static WeakReference<OnPriceReceivedListener> sPriceListener = new WeakReference<>(null);
@NonNull
private static WeakReference<OnInfoReceivedListener> sInfoListener = new WeakReference<>(null);
@Nullable
private String mId;
final String rating;
final String price;
final String urlBook;
final String urlDescription;
@NonNull
final String mRating;
@NonNull
final String mPrice;
@NonNull
final String mUrlBook;
@NonNull
final String mUrlDescription;
public SponsoredHotel(String rating, String price, String urlBook, String urlDescription)
public SponsoredHotel(@NonNull String rating, @NonNull String price, @NonNull String urlBook,
@NonNull String urlDescription)
{
this.rating = rating;
this.price = price;
this.urlBook = urlBook;
this.urlDescription = urlDescription;
mRating = rating;
mPrice = price;
mUrlBook = urlBook;
mUrlDescription = urlDescription;
}
void updateId(MapObject point)
@ -55,61 +196,107 @@ public final class SponsoredHotel
mId = point.getMetadata(Metadata.MetadataType.FMD_SPONSORED_ID);
}
@Nullable
public String getId()
{
return mId;
}
@NonNull
public String getRating()
{
return rating;
return mRating;
}
@NonNull
public String getPrice()
{
return price;
return mPrice;
}
@NonNull
public String getUrlBook()
{
return urlBook;
return mUrlBook;
}
@NonNull
public String getUrlDescription()
{
return urlDescription;
return mUrlDescription;
}
public static void setListener(OnPriceReceivedListener listener)
static void setPriceListener(@NonNull OnPriceReceivedListener listener)
{
sListener = new WeakReference<>(listener);
sPriceListener = new WeakReference<>(listener);
}
static void setInfoListener(@NonNull OnInfoReceivedListener listener)
{
sInfoListener = new WeakReference<>(listener);
}
/**
* Make request to obtain hotel price information.
* This method also checks cache for requested hotel id
* and if cache exists - call {@link #onPriceReceived(String, String, String) onPriceReceived} immediately
*
* @param id A Hotel id
* @param currencyCode A user currency
*/
static void requestPrice(String id, String currencyCode)
{
Price p = sPriceCache.get(id);
if (p != null)
onPriceReceived(id, p.price, p.currency);
onPriceReceived(id, p.mPrice, p.mCurrency);
nativeRequestPrice(id, currencyCode);
}
@SuppressWarnings("unused")
private static void onPriceReceived(String id, String price, String currency)
/**
* Make request to obtain hotel information.
* This method also checks cache for requested hotel id
* and if cache exists - call {@link #onInfoReceived(String, HotelInfo) onInfoReceived} immediately
*
* @param id A Hotel id
* @param locale A user locale
*/
static void requestInfo(String id, String locale)
{
HotelInfo info = sInfoCache.get(id);
if (info != null)
onInfoReceived(id, info);
nativeRequestInfo(id, locale);
}
private static void onPriceReceived(@NonNull String id, @NonNull String price,
@NonNull String currency)
{
if (TextUtils.isEmpty(price))
return;
sPriceCache.put(id, new Price(price, currency));
OnPriceReceivedListener listener = sListener.get();
if (listener == null)
sListener = null;
else
OnPriceReceivedListener listener = sPriceListener.get();
if (listener != null)
listener.onPriceReceived(id, price, currency);
}
private static void onInfoReceived(@NonNull String id, @NonNull HotelInfo info)
{
sInfoCache.put(id, info);
OnInfoReceivedListener listener = sInfoListener.get();
if (listener != null)
listener.onInfoReceived(id, info);
}
@Nullable
public static native SponsoredHotel nativeGetCurrent();
private static native void nativeRequestPrice(String id, String currencyCode);
private static native void nativeRequestPrice(@NonNull String id, @NonNull String currencyCode);
private static native void nativeRequestInfo(@NonNull String id, @NonNull String locale);
}

View file

@ -0,0 +1,131 @@
package com.mapswithme.maps.widget.recycler;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Adds interior dividers to a RecyclerView with a LinearLayoutManager or its
* subclass.
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration
{
@NonNull
private final Drawable mDivider;
private int mOrientation;
/**
* Sole constructor. Takes in a {@link Drawable} to be used as the interior
* divider.
*
* @param divider A divider {@code Drawable} to be drawn on the RecyclerView
*/
public DividerItemDecoration(@NonNull Drawable divider)
{
mDivider = divider;
}
/**
* Draws horizontal or vertical dividers onto the parent RecyclerView.
*
* @param canvas The {@link Canvas} onto which dividers will be drawn
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state)
{
if (mOrientation == LinearLayoutManager.HORIZONTAL)
drawHorizontalDividers(canvas, parent);
else if (mOrientation == LinearLayoutManager.VERTICAL)
drawVerticalDividers(canvas, parent);
}
/**
* Determines the size and location of offsets between items in the parent
* RecyclerView.
*
* @param outRect The {@link Rect} of offsets to be added around the child
* view
* @param view The child view to be decorated with an offset
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
super.getItemOffsets(outRect, view, parent, state);
if (parent.getChildAdapterPosition(view) == 0)
return;
mOrientation = ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
if (mOrientation == LinearLayoutManager.HORIZONTAL)
outRect.left = mDivider.getIntrinsicWidth();
else if (mOrientation == LinearLayoutManager.VERTICAL)
outRect.top = mDivider.getIntrinsicHeight();
}
/**
* Adds dividers to a RecyclerView with a LinearLayoutManager or its
* subclass oriented horizontally.
*
* @param canvas The {@link Canvas} onto which horizontal dividers will be
* drawn
* @param parent The RecyclerView onto which horizontal dividers are being
* added
*/
private void drawHorizontalDividers(Canvas canvas, RecyclerView parent)
{
int parentTop = parent.getPaddingTop();
int parentBottom = parent.getHeight() - parent.getPaddingBottom();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++)
{
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int parentLeft = child.getRight() + params.rightMargin;
int parentRight = parentLeft + mDivider.getIntrinsicWidth();
mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
mDivider.draw(canvas);
}
}
/**
* Adds dividers to a RecyclerView with a LinearLayoutManager or its
* subclass oriented vertically.
*
* @param canvas The {@link Canvas} onto which vertical dividers will be
* drawn
* @param parent The RecyclerView onto which vertical dividers are being
* added
*/
private void drawVerticalDividers(Canvas canvas, RecyclerView parent)
{
int parentLeft = parent.getPaddingLeft();
int parentRight = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++)
{
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int parentTop = child.getBottom() + params.bottomMargin;
int parentBottom = parentTop + mDivider.getIntrinsicHeight();
mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
mDivider.draw(canvas);
}
}
}

View file

@ -0,0 +1,128 @@
package com.mapswithme.maps.widget.recycler;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Adds interior dividers to a RecyclerView with a GridLayoutManager.
*/
public class GridDividerItemDecoration extends RecyclerView.ItemDecoration
{
@NonNull
private final Drawable mHorizontalDivider;
@NonNull
private final Drawable mVerticalDivider;
private final int mNumColumns;
/**
* Sole constructor. Takes in {@link Drawable} objects to be used as
* horizontal and vertical dividers.
*
* @param horizontalDivider A divider {@code Drawable} to be drawn on the
* rows of the grid of the RecyclerView
* @param verticalDivider A divider {@code Drawable} to be drawn on the
* columns of the grid of the RecyclerView
* @param numColumns The number of columns in the grid of the RecyclerView
*/
public GridDividerItemDecoration(@NonNull Drawable horizontalDivider,
@NonNull Drawable verticalDivider, int numColumns)
{
mHorizontalDivider = horizontalDivider;
mVerticalDivider = verticalDivider;
mNumColumns = numColumns;
}
/**
* Draws horizontal and/or vertical dividers onto the parent RecyclerView.
*
* @param canvas The {@link Canvas} onto which dividers will be drawn
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state)
{
drawHorizontalDividers(canvas, parent);
drawVerticalDividers(canvas, parent);
}
/**
* Determines the size and location of offsets between items in the parent
* RecyclerView.
*
* @param outRect The {@link Rect} of offsets to be added around the child view
* @param view The child view to be decorated with an offset
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
super.getItemOffsets(outRect, view, parent, state);
boolean childIsInLeftmostColumn = (parent.getChildAdapterPosition(view) % mNumColumns) == 0;
if (!childIsInLeftmostColumn)
outRect.left = mHorizontalDivider.getIntrinsicWidth();
boolean childIsInFirstRow = (parent.getChildAdapterPosition(view)) < mNumColumns;
if (!childIsInFirstRow)
outRect.top = mVerticalDivider.getIntrinsicHeight();
}
/**
* Adds horizontal dividers to a RecyclerView with a GridLayoutManager or
* its subclass.
*
* @param canvas The {@link Canvas} onto which dividers will be drawn
* @param parent The RecyclerView onto which dividers are being added
*/
private void drawHorizontalDividers(Canvas canvas, RecyclerView parent)
{
int parentTop = parent.getPaddingTop();
int parentBottom = parent.getHeight() - parent.getPaddingBottom();
for (int i = 0; i < mNumColumns; i++)
{
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int parentLeft = child.getRight() + params.rightMargin;
int parentRight = parentLeft + mHorizontalDivider.getIntrinsicWidth();
mHorizontalDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
mHorizontalDivider.draw(canvas);
}
}
/**
* Adds vertical dividers to a RecyclerView with a GridLayoutManager or its
* subclass.
*
* @param canvas The {@link Canvas} onto which dividers will be drawn
* @param parent The RecyclerView onto which dividers are being added
*/
private void drawVerticalDividers(Canvas canvas, RecyclerView parent)
{
int parentLeft = parent.getPaddingLeft();
int parentRight = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
int numRows = (childCount + (mNumColumns - 1)) / mNumColumns;
for (int i = 0; i < numRows - 1; i++)
{
View child = parent.getChildAt(i * mNumColumns);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int parentTop = child.getBottom() + params.bottomMargin;
int parentBottom = parentTop + mVerticalDivider.getIntrinsicHeight();
mVerticalDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
mVerticalDivider.draw(canvas);
}
}
}

View file

@ -7,6 +7,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.AnyRes;
@ -19,6 +20,7 @@ import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewTreeObserver;
@ -339,6 +341,24 @@ public final class UiUtils
return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
}
public static boolean isViewTouched(@NonNull MotionEvent event, @NonNull View view)
{
if (UiUtils.isHidden(view))
return false;
int x = (int) event.getX();
int y = (int) event.getY();
int[] location = new int[2];
view.getLocationOnScreen(location);
int viewX = location[0];
int viewY = location[1];
int width = view.getWidth();
int height = view.getHeight();
Rect viewRect = new Rect(viewX, viewY, viewX + width, viewY + height);
return viewRect.contains(x, y);
}
// utility class
private UiUtils() {}
}

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "المزيد";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "حجز";
"placepage_call_button" = "اتصال";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "توفير عند حجز الفنادق";
"whats_new_booking_improve_message" = "تحتوي نتائج البحث عن الفنادق الآن على فئة السعر.\nوأضفنا أيضًا أكثر من 110000 فندق.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Více";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Rezervace";
"placepage_call_button" = "Volat";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Ušetřete při rezervaci hotelů";
"whats_new_booking_improve_message" = "Výsledky hledání hotelů nyní obsahují cenové kategorie. \nTaké jsme přidali více než 110 000 hotelů.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Mere";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Bog";
"placepage_call_button" = "Ring";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Spar penge når du bestiller hotelværelser";
"whats_new_booking_improve_message" = "Søgeresultater for hoteller viser nu også priskategorien.\nVi har desuden tilføjet mere end 110.000 hoteller.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Mehr";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Buchen";
"placepage_call_button" = "Anruf";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Beim Buchen von Hotels sparen";
"whats_new_booking_improve_message" = "Suchergebnisse für Hotels enthalten jetzt die Kategorie Preis.\nAußerdem haben wir über 110.000 Hotels hinzugefügt.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "More";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Book";
"placepage_call_button" = "Call";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Save when booking hotels";
"whats_new_booking_improve_message" = "Search results for hotels now contain the price category.\nWe also added more than 110,000 hotels.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "More";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Book";
"placepage_call_button" = "Call";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Save when booking hotels";
"whats_new_booking_improve_message" = "Search results for hotels now contain the price category.\nWe also added more than 110,000 hotels.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Más";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Reservar";
"placepage_call_button" = "Llamar";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Ahorrar al reservar hoteles";
"whats_new_booking_improve_message" = "La búsqueda de resultados de hoteles ahora contiene la categoría de precios.\nHemos añadido más de 110 000 hoteles.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Lisää";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Varaa";
"placepage_call_button" = "Soita";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Säästä hotellivarauksissa";
"whats_new_booking_improve_message" = "Hotellien hakutuloksissa näkyy nyt hintakategoria.\nLisäsimme myös yli 110 000 hotellia.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Plus";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Réserver";
"placepage_call_button" = "Appeler";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Économisez de l'argent en réservant des hôtels";
"whats_new_booking_improve_message" = "Les résultats des recherches d'hôtels comprennent maintenant la catégorie de prix.\nNous avons aussi ajouté plus de 110.000 hôtels.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Még";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Foglalás";
"placepage_call_button" = "Hívás";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Takarékoskodjon szálláshely foglalásakor";
"whats_new_booking_improve_message" = "A szálláshely keresési eredménye már tartalmazza az árkategóriát. \nEmellett kiegészítettük több mint 110.000 szálláshellyel.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Lainnya";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Pesan";
"placepage_call_button" = "Hubungi";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Berhemat saat memesan hotel";
"whats_new_booking_improve_message" = "Hasil pencarian untuk hotel kini disertai kategori harga.\nKami juga menambahkan lebih dari 110.000 hotel.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Altro";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Prenota";
"placepage_call_button" = "Chiama";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Risparmia alla prenotazione degli hotel";
"whats_new_booking_improve_message" = "I risultati della ricerca per gli hotel contengono ora la categoria di prezzo.\nInoltre, abbiamo aggiunto più di 110.000 hotel.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "さらに詳しく";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "予約";
"placepage_call_button" = "コール";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "ホテル予約時に節約しましょう";
"whats_new_booking_improve_message" = "ホテルの検索結果に価格のカテゴリーが表示されるようになりました。\nさらに、 110,000 軒を超えるホテルを追加しました。";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "자세히";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "예약";
"placepage_call_button" = "전화";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "호텔 예약 시 절약";
"whats_new_booking_improve_message" = "이제 가격 범주를 포함하는 호텔에 대한 결과를 검색하세요.\n또한 110,000곳 이상의 호텔이 추가되었습니다.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Mer";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Bestill";
"placepage_call_button" = "Ring";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Spar penger når du bestiller hotell";
"whats_new_booking_improve_message" = "Søkeresultatene for hoteller inneholder nå priskategori.\nVi har også lagt til flere enn 110.000 hoteller.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Meer";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Boeken";
"placepage_call_button" = "Bellen";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Bespaar op het boeken van hotels";
"whats_new_booking_improve_message" = "Zoekresultaten voor hotels bevatten nu de prijscategorie.\nWe hebben ook meer dan 110.000 hotels toegevoegd.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Więcej";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Zarezerwuj";
"placepage_call_button" = "Zadzwoń";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Oszczędzaj przy rezerwacji hotelów";
"whats_new_booking_improve_message" = "Wyniki wyszukiwania hoteli zawierają teraz kategorię cenową. \nDodaliśmy też ponad 110 000 hoteli.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Mais";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Livro";
"placepage_call_button" = "Chamada";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Poupe nas reservas de hotéis";
"whats_new_booking_improve_message" = "Agora, os resultados da pesquisa de hotéis contêm a categoria de preços.\nAdicinámos mais de 110.000 hotéis.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Mai multe";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Rezervare";
"placepage_call_button" = "Apel";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Economisiți bani când rezervați hoteluri";
"whats_new_booking_improve_message" = "Rezultatele de căutare pentru hoteluri conțin acum categoria de preț. \nAm mai adăugat și peste 110.000 de hoteluri.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Ещё";
"placepage_more_reviews_button" = "Ещё отзывы";
"bookingcom_book_button" = "Забронировать";
"placepage_call_button" = "Позвонить";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Экономь на бронировании отеля";
"whats_new_booking_improve_message" = "Результаты поиска отелей на карте показывают ценовую категорию.\nОтелей для бронирования стало на 110 000 больше.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Удобства";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Рядом";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Viac";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Rezervovať";
"placepage_call_button" = "Zavolať";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Ušetriť pri rezervácii hotelov";
"whats_new_booking_improve_message" = "Výsledky vyhľadávania hotelov odteraz obsahujú aj cenové kategórie. \nTiež sme pridali viac ako 110 000 hotelov.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Mer";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Boka";
"placepage_call_button" = "Ring";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Spara pengar när du bokar hotell";
"whats_new_booking_improve_message" = "Sökresultat för hotell innehåller nu priskategorin.\nVi har även lagt till över 110 000 hotell.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "เพิ่มเติม";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "จอง";
"placepage_call_button" = "โทร";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "ประหยัดเมื่อจองโรงแรม";
"whats_new_booking_improve_message" = "การค้นหาโรงแรมตอนนี้มีหมวดหมู่ราคาแล้ว\nเรายังได้เพิ่มโรงแรมเข้ามากว่า 110,000 โรงแรมอีกด้วย";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

View file

@ -1474,6 +1474,8 @@
"placepage_more_button" = "Diğer";
"placepage_more_reviews_button" = "More Reviews";
"bookingcom_book_button" = "Rezervasyon";
"placepage_call_button" = "Çağrı";
@ -1626,3 +1628,9 @@
"whats_new_booking_improve_title" = "Otel rezervasyonlarınızdan tasarruf edin";
"whats_new_booking_improve_message" = "Artık otel arama sonuçlarında fiyat kategorisi de gösteriliyor.\nVe 110,000'den fazla oteli sistemimize ekledik.";
/* For place page hotel facilities block */
"placepage_hotel_facilities" = "Facilities";
/* For place page hotel nearby block */
"placepage_hotel_nearby" = "Nearby";

Some files were not shown because too many files have changed in this diff Show more