Компонент Advanced Place Details

Расширенная версия компонента Place Details предлагает те же функции, что и Places Details Essentials. Вы также можете выбрать, будет ли показываться название места, настроить командные кнопки компонента и применить параметры поиска и фильтрации к показываемым отзывам и медиафайлам.

Расширенная конфигурация Place Details

Чтобы получить доступ к продвинутым функциям, используйте AdvancedPlaceDetailsView или AdvancedPlaceDetailsCompactView.

Параметры показа контента

Вы можете указать, какой контент показывать, используя перечисления в AdvancedPlaceDetailsContent. Вы можете настроить весь контент, доступный в Places Details Essentials, а также выбрать, будет ли показываться название места.

Как настроить командные кнопки

Чтобы удалить или настроить командные кнопки, используйте методы .cornerActions и .mainActions класса AdvancedPlaceDetailsView или AdvancedPlaceDetailsCompactView.

Требования к визуальному указанию авторства

Компактный вид информации о местах с настраиваемыми кнопками
Компактный вид расширенной информации о месте с настраиваемой кнопкой

Важно! Вы должны четко сообщить конечным пользователям, что при нажатии кнопки настраиваемого действия их данные будут переданы третьей стороне, не связанной с Google. Подробнее о требованиях по указанию авторства…

На примере справа показано специальное изображение, из которого понятно, что информация о пользователе будет отправлена в Altostrat.

Как использовать поиск и фильтры

Используйте методы .searchMediaOptions и .searchReviewOptions из AdvancedPlaceDetailsView или AdvancedPlaceDetailsCompactView, чтобы включить поиск и фильтрацию медиаконтента или отзывов.

Как создавать собственные рекламные места

Варианты размещения рекламных мест для собственного контента

С помощью специальных рекламных мест вы можете добавлять собственный контент (например, сводки, созданные ИИ, временные метки маршрута или специальные значки) непосредственно в предопределенные зоны макета.

Чтобы добавить пользовательские стили контента, используйте метод .placeDetailsCompactContentSlot класса AdvancedPlaceDetailsCompactView. Доступны позиции .basicSectionTop и .basicSectionBottom.

Требования по указанию авторства и рекомендации по контенту для слотов контента

Когда встраивается рекламное место для собственного контента, раскрытие информации автоматически обновляется, чтобы уточнить, какой контент предоставляется Google, а какой – третьими лицами.

Значки должны:

Поддерживайте четкую визуальную иерархию между информацией о местах Google и собственным контентом, чтобы у пользователей не возникало сомнений в источнике информации.

Указывайте источник информации

Значки должны:

Предоставляйте пользователям локализованную и ценную информацию, которая поможет им достичь своих целей. Например, данные о доступности номеров в реальном времени или о сроках бронирования помогут пользователям быстрее принимать взвешенные решения.

Предоставлять ценную статистику

Чего не следует делать

Не дублируйте существующую информацию о местах в Google, такую как оценки, отзывы или часы работы, даже если вы скрыли контент, предоставленный Google. В противном случае пользователи могут не понять, откуда поступает контент – от Google или от стороннего поставщика.

Не дублируйте существующую информацию о местах в Google.

Чего не следует делать

Не используйте заявления и значки без указания авторства (например, "Лучшая рекомендация!"), которые могут быть ошибочно приняты за официальные рекомендации Google. В пользовательском контенте должен быть явно указан источник.

Не показывайте утверждения или значки без указания авторства.

Чего не следует делать

Не добавляйте в контейнеры пользовательских мест рекламу, маркетинговые тексты, скидки и предложения оформить подписку.

Не добавляйте рекламу, маркетинговые тексты, скидки и предложения оформить подписку.

Примеры расширенных сведений о месте

Не указывайте название места.

Чтобы не указывать название места, не добавляйте .name в параметр content в AdvancedPlaceDetailsConfiguration.

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  // Query for loading the place details component.
  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )
  @State private var favoritePlaces: Set<String> = []

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content:[.address()],
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { result in
        if let place = result.place {
          print("Place: \(place.description)")
        } else {
          print("Error: \(String(describing: result.error))")
        }
      }
    )
  }
}

Как удалить командные кнопки

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content: AdvancedPlaceDetailsView.allContent,
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { result in
        if let place = result.place {
          print("Place: \(place.description)")
        } else {
          print("Error: \(String(describing: result.error))")
        }
      }
    )
    .mainActions{ _ in
      return []
    }
  }
}

Добавление специальных и стандартных действий

В этом примере пользователю предлагается добавить место в избранное или удалить его оттуда, а также выполнить стандартное действие Открыть в Картах.

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )
  
  @State var favoritePlaces: Set<String> = []

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content: AdvancedPlaceDetailsView.allContent,
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { result in
        if let place = result.place {
          print("Place: \(place.description)")
        } else {
          print("Error: \(String(describing: result.error))")
        }
      }
    )
    .mainActions{ place in
      var actions: [MainPlaceActionElement] = []
      let placeID = place.placeID!
      if self.favoritePlaces.contains(placeID) {
        actions.append(
          .action(
            MainPlaceAction(
              image: Image(systemName: "heart.fill"),
              label: "Unfavorite"
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      } else {
        actions.append(
          .action(
            MainPlaceAction(
              image: Image(systemName: "heart"),
              label: "Favorite"
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      }
      actions.append(.actionId(.openMap(style: .primary)))
      return actions
    }
    .cornerActions { place in
      var actions: [CornerPlaceActionElement] = []
      let placeID = place.placeID!
      if self.favoritePlaces.contains(placeID) {
        actions.append(
          .action(
            CornerPlaceAction(
              image: Image(systemName: "heart.fill"),
              accessibilityLabel: "Unfavorite",
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      } else {
        actions.append(
          .action(
            CornerPlaceAction(
              image: Image(systemName: "heart"),
              accessibilityLabel: "Favorite",
            ) { _ in self.toggleFavorite(placeID) }
          )
        )
      }
      actions.append(.actionId(.openMap(style: .primary)))
      return actions
    }
  }

  func toggleFavorite(_ placeID: String) {
    if favoritePlaces.contains(placeID) {
      favoritePlaces.remove(placeID)
    } else {
      favoritePlaces.insert(placeID)
    }
  }
}

Фильтровать отзывы и медиаконтент

В этом примере кода показаны только медиафайлы и отзывы, в которых упоминается кофе.

Swift

struct DemoView: View {
  static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

  @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
    identifier: .placeID(peetsCoffeePlaceID)
  )
  let searchMediaOptions = SearchMediaOptions(query: "coffee")
  let searchReviewsOptions = SearchReviewsOptions(query: "coffee")

  var body: some View {
    AdvancedPlaceDetailsView(
      query: $query,
      configuration: AdvancedPlaceDetailsConfiguration(
        content: [.media(), .reviews()],
        theme: PlacesMaterialTheme()
      ),
      placeDetailsCallback: { _ in }
    )
    .searchMediaOptions(searchMediaOptions) { results in
      guard let result = results.first else { return }
      switch result {
      case .success(let summary):
        print("Summary: \(summary)")
      case .failure(let error):
        print("Error: \(error)")
      }
    }
    .searchReviewsOptions(searchReviewsOptions) { results in
      guard let result = results.first else { return }
      switch result {
      case .success(let summary):
        print("Summary: \(summary)")
      case .failure(let error):
        print("Error: \(error)")
      }
    }
  }
}

Как создать рекламные места

В этом примере контент добавляется в рекламные места basicSectionTop и basicSectionBottom.

Swift

import SwiftUI
import PlacesSwift

struct ItineraryCard: View {
    static let peetsCoffeePlaceID = "ChIJT7FdmYiAhYAROFOvrIxRJDU"

    @State var query: PlaceDetailsQuery = PlaceDetailsQuery(
      identifier: .placeID(peetsCoffeePlaceID)
    )

    var body: some View {
      AdvancedPlaceDetailsCompactView(
        orientation: .vertical,
        query: $query,
        configuration: AdvancedPlaceDetailsCompactConfiguration(
          content: AdvancedPlaceDetailsCompactView.allContent,
          theme: PlacesMaterialTheme()
        ),
        placeDetailsCallback: { _ in }
      )
      .placeDetailsCompactContentSlot(position: .basicSectionTop) { place in
        Text("Day 2 • 2:30 PM")
          .font(.caption)
          .fontWeight(.bold)
          .foregroundColor(.accentColor)
      }
      .placeDetailsCompactContentSlot(position: .basicSectionBottom) { place in
        VStack(alignment: .leading, spacing: 4) {
          Text("AI Notes")
            .font(.caption)
            .bold()
          Text("Great quiet atmosphere for morning meetings. Famous for house-roasted pour-overs.")
            .font(.footnote)
            .foregroundColor(.secondary)
        }
        .padding(8)
        .background(Color(.systemGray6))
        .cornerRadius(8)
      }
    }
}