Composant Advanced Place Details

La version avancée du composant Place Details offre les mêmes fonctionnalités que Places Details Essentials. Il vous permet également de choisir d'afficher ou non le nom du lieu, de configurer les boutons d'action du composant et d'appliquer des options de recherche et de filtrage aux avis et aux contenus multimédias affichés.

Configuration avancée des détails du lieu

Utilisez AdvancedPlaceDetailsView ou AdvancedPlaceDetailsCompactView pour accéder aux fonctionnalités avancées.

Options d'affichage du contenu

Vous pouvez spécifier le contenu à afficher à l'aide des énumérations dans AdvancedPlaceDetailsContent. Vous pouvez configurer le même contenu que Places Details Essentials et choisir d'afficher ou non le nom du lieu.

Configurer les boutons d'action

Utilisez les méthodes .cornerActions et .mainActions de AdvancedPlaceDetailsView ou AdvancedPlaceDetailsCompactView pour supprimer ou personnaliser les boutons d'action.

Exigences concernant l'attribution visuelle

Vue compacte des détails du lieu avec des boutons personnalisés
Vue compacte avancée des détails du lieu avec bouton personnalisé

Important : Vous devez indiquer clairement aux utilisateurs finaux quand un bouton d'action personnalisée partagera des informations utilisateur avec un tiers autre que Google. Consultez les exigences concernant l'attribution visuelle.

L'exemple de droite montre une image personnalisée qui indique clairement que les informations utilisateur seront envoyées à "Altostrat".

Appliquer des options de recherche et de filtrage

Utilisez les méthodes .searchMediaOptions et .searchReviewOptions de AdvancedPlaceDetailsView ou AdvancedPlaceDetailsCompactView pour activer la recherche et le filtrage des contenus multimédias ou des avis.

Créer des emplacements de contenu personnalisés

Options de placement des emplacements de contenu personnalisé

Les emplacements de contenu personnalisés vous permettent d'ajouter votre propre contenu (comme des résumés générés par l'IA, des codes temporels d'itinéraires ou des badges personnalisés) directement dans des zones de mise en page prédéfinies.

Pour ajouter des contenus personnalisés, utilisez la méthode .placeDetailsCompactContentSlot de AdvancedPlaceDetailsCompactView. Les positions disponibles sont .basicSectionTop et .basicSectionBottom.

Exigences d'attribution et suggestions de contenu pour les emplacements de contenu

Lorsqu'un emplacement de contenu personnalisé est monté, la clause de non-responsabilité est automatiquement mise à jour pour préciser quel contenu est fourni par Google et quel contenu est fourni par des tiers.

À faire

Maintenez une hiérarchie visuelle claire entre les détails des établissements Google et le contenu personnalisé pour éviter toute ambiguïté sur la source des informations.

Éviter toute ambiguïté concernant la source d'informations

À faire

Pensez à des insights localisés à forte valeur ajoutée, adaptés aux objectifs immédiats de vos utilisateurs. Les contenus personnalisés, tels que les créneaux de réservation en temps réel ou la disponibilité actuelle, aident les utilisateurs à prendre des décisions plus rapidement et de manière plus éclairée.

Fournir des insights à forte valeur ajoutée

À éviter

Ne dupliquez pas les informations existantes sur les établissements Google, comme les notes, les avis ou les horaires d'ouverture, même si vous avez masqué le contenu fourni par Google. Cela peut dérouter les utilisateurs quant à la source du contenu et à son origine (Google ou un tiers).

Ne pas dupliquer les informations existantes sur les établissements Google

À éviter

N'affichez pas d'affirmations ou de badges non attribués (par exemple, "Recommandation n° 1 !") qui pourraient être confondus avec des mentions officielles de Google. Le contenu personnalisé doit indiquer explicitement sa source.

Ne pas afficher les affirmations ou les badges non attribués

À éviter

N'incluez pas d'annonces, de textes marketing, de remises promotionnelles ni d'invites à s'abonner dans les conteneurs d'emplacements personnalisés.

N'incluez pas d'annonces, de textes marketing, de remises promotionnelles ni d'invites à s'abonner.

Exemples avancés de Place Details

Omettre le nom du lieu

Pour omettre le nom du lieu, n'incluez pas .name dans le paramètre content de 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))")
        }
      }
    )
  }
}

Supprimer les boutons d'action

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 []
    }
  }
}

Ajouter des actions personnalisées et prédéfinies

Cet exemple ajoute une option permettant à un utilisateur de marquer un lieu comme favori ou de le supprimer de ses favoris, ainsi que l'action prédéfinie Ouvrir dans Maps.

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)
    }
  }
}

Filtrer les avis et les contenus multimédias

Cet exemple de code n'affiche que les contenus multimédias et les avis mentionnant le mot "café".

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)")
      }
    }
  }
}

Créer des emplacements de contenu

Cet exemple ajoute du contenu aux emplacements basicSectionTop et 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)
      }
    }
}