Migracja z wersji Material 2.5 na Material 3 w Compose na Wear OS

Material 3 Expressive to kolejna wersja Material Design. Obejmuje ona zaktualizowane motywy, komponenty i funkcje personalizacji, takie jak dynamiczny kolor.

Ten przewodnik dotyczy migracji z biblioteki Jetpack Wear Compose Material 2.5 (androidx.wear.compose) na Wear Compose Material 3 (androidx.wear.compose.material3) na potrzeby aplikacji.

Podejścia

Aby przenieść kod aplikacji z poziomu M2.5 na M3, postępuj zgodnie z instrukcjami opisanymi w artykule Compose Material – wskazówki dotyczące migracji na telefony, w szczególności:

Zależności

M3 ma oddzielny pakiet i wersję w porównaniu z M2.5:

M2,5

implementation("androidx.wear.compose:compose-material:1.4.0")

M3

implementation("androidx.wear.compose:compose-material3:1.5.0-beta01")

Najnowsze wersje M3 znajdziesz na stronie z wersjami Wear Compose Material 3.

Wersja 1.5.0-beta01 biblioteki Compose Foundation na Wear OS wprowadza kilka nowych komponentów zaprojektowanych do współpracy z komponentami Material 3. Podobnie element SwipeDismissableNavHost z biblioteki Wear Compose Navigation ma zaktualizowaną animację, gdy jest uruchamiany na Wear OS 6 (poziom interfejsu API 36) lub nowszym. Podczas aktualizacji do wersji Material 3 na Wear Compose zalecamy też zaktualizowanie bibliotek Wear Compose Foundation i Navigation:

implementation("androidx.wear.compose:compose-foundation:1.5.0-beta01")
implementation("androidx.wear.compose:compose-navigation:1.5.0-beta01")

Motywy

Zarówno w wersji M2.5, jak i M3 kompozyt tematyczny ma nazwę MaterialTheme, ale pakiety importowania i parametry różnią się. W M3 parametr Colors został przemianowany na ColorScheme, a do implementacji przejść został wprowadzony parametr MotionScheme.

M2,5

import androidx.wear.compose.material.MaterialTheme

MaterialTheme(
        colors = AppColors,
        typography = AppTypography,
        shapes = AppShapes,
        content = content
)

M3

import androidx.wear.compose.material3.MaterialTheme

MaterialTheme(
        colorScheme = AppColorScheme,
        typography = AppTypography,
        shapes = AppShapes,
        motionScheme = AppMotionScheme,
        content = content
)

Kolor

System kolorów w M3 różni się znacznie od M2.5. Liczba parametrów kolorów wzrosła, mają one różne nazwy i różnie mapowania do komponentów M3. W edytorze dotyczy to klasy M2.5 Colors, klasy M3 ColorScheme i powiązanych funkcji:

M2,5

import androidx.wear.compose.material.Colors

val appColorScheme: Colors = Colors(
   // M2.5 Color parameters
)

M3

import androidx.wear.compose.material3.ColorScheme

val appColorScheme: ColorScheme = ColorScheme(
   // M3 ColorScheme parameters
)

W tej tabeli opisano główne różnice między wersjami M2.5 i M3:

M2,5

M3

Color

została zmieniona na ColorScheme

13 kolorów

28 kolorów

Nie dotyczy

nowe dynamiczne motywy kolorystyczne

Nie dotyczy

nowe kolory dodatkowe, które pozwalają na większą ekspresję;

Dynamiczne motywy kolorystyczne

Nowością w M3 jest dynamiczne motywy kolorystyczne. Jeśli użytkownicy zmienią kolory tarczy zegarka, kolory w interfejsie zostaną dopasowane.

Aby zaimplementować dynamiczny schemat kolorów, użyj funkcji dynamicColorScheme i podaj wartość defaultColorScheme jako wartość zastępczą na wypadek, gdyby dynamiczny schemat kolorów był niedostępny.

@Composable
fun myApp() {
  val myColorScheme = myBrandColors()
  val dynamicColorScheme = dynamicColorScheme(LocalContext.current)
  MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {...}
}

Typografia

System typograficzny w M3 różni się od tego w M2 i obsługuje te funkcje:

  • 9 nowych stylów tekstu
  • czcionki elastyczne, które umożliwiają dostosowywanie skali czcionki do różnych grubości, szerokości i kształtów zaokrągleń;
  • AnimatedText, który używa czcionek elastycznych

M2,5

import androidx.wear.compose.material.Typography

val Typography = Typography(
   // M2.5 TextStyle parameters
)

M3

import androidx.wear.compose.material3.Typography

val Typography = Typography(
   // M3 TextStyle parameters
)

Flex Fonts

Czcionki elastyczne umożliwiają projektantom określanie szerokości i grubości czcionki w przypadku konkretnych rozmiarów.

Style tekstu

W M3 dostępne są te style tekstu: Są one domyślnie używane przez różne komponenty M3.

Typografia

TextStyle

Wyświetlacz

displayLarge, displayMedium, displaySmall

Tytuł

titleLarge, titleMedium, titleSmall

Etykieta

labelLarge, labelMedium, labelSmall

Treść

bodyLarge, bodyMedium, bodySmall, bodyExtraSmall

Cyfry

numeralExtraLarge, numeralLarge, numeralMedium, numeralSmall, numeralExtraSmall

Łuk

arcLarge, arcMedium, arcSmall

Kształt

System kształtów w M3 różni się od tego w M2. Zwiększono liczbę parametrów kształtu, zmieniono ich nazwy i sposób mapowania na komponenty M3. Dostępne są te rozmiary kształtów:

  • Bardzo mały
  • Mały
  • średni,
  • Duży
  • Bardzo duży

W Compose dotyczy to klasy Shapes (M2) i klasy Shapes (M3):

M2,5

import androidx.wear.compose.material.Shapes

val Shapes = Shapes(
   // M2.5 Shapes parameters
)

M3

import androidx.wear.compose.material3.Shapes

val Shapes = Shapes(
   // M3 Shapes parameters
)

Jako punkt wyjścia użyj mapowania parametrów kształtów z artykułu Przejście z Material 2 na Material 3 w Compose.

Przekształcanie kształtu

M3 wprowadza przekształcanie kształtów: kształty zmieniają się w reakcji na interakcje.

Funkcja przekształcania kształtu jest dostępna jako wariant dla wielu okrągłych przycisków. Poniżej znajdziesz przykłady:

Przyciski

Funkcja przekształcania kształtu

IconButton

Funkcja IconButtonDefaults.animatedShape() animuje przycisk ikony po naciśnięciu.

IconToggleButton

Funkcja IconToggleButtonDefaults.animatedShape() animuje przycisk przełącznika ikony po naciśnięciu i

IconToggleButtonDefaults.variantAnimatedShapes() animuje przycisk przełącznika ikony po naciśnięciu oraz zaznaczeniu lub odznaczeniu.

TextButton

TextButtonDefaults.animatedShape() powoduje animację przycisku tekstowego po naciśnięciu.

TextToggleButton

TextToggleButtonDefaults.animatedShapes() animuje przełącznik tekstu po naciśnięciu, a TextToggleButtonDefaults.variantAnimatedShapes() animuje przełącznik tekstu po naciśnięciu i zaznaczeniu lub odznaczeniu.

Komponenty i układ

Większość komponentów i schematów z wersji M2.5 jest dostępna w wersji M3. Niektóre komponenty i układy M3 nie były jednak dostępne w wersji M2.5. Co więcej, niektóre komponenty M3 mają więcej odmian niż ich odpowiedniki w M2.5.

Chociaż niektóre komponenty wymagają szczególnej uwagi, jako punkt wyjścia zalecamy użycie tych map funkcji:

Material 2.5

Materiał 3

androidx.wear.compose.material.dialog.Alert

androidx.wear.compose.material3.AlertDialog

androidx.wear.compose.material.Button

androidx.wear.compose.material3.IconButton lub androidx.wear.compose.material3.TextButton

androidx.wear.compose.material.Card

androidx.wear.compose.material3.Card

androidx.wear.compose.material.TitleCard

androidx.wear.compose.material3.TitleCard

androidx.wear.compose.material.AppCard

androidx.wear.compose.material3.AppCard

androidx.wear.compose.material.Checkbox

Brak odpowiednika w Androidzie 3.0, należy przejść na androidx.wear.compose.material3.CheckboxButton lub androidx.wear.compose.material3.SplitCheckboxButton

androidx.wear.compose.material.Chip

androidx.wear.compose.material3.Button lub
androidx.wear.compose.material3.OutlinedButton lub
androidx.wear.compose.material3.FilledTonalButton lub
androidx.wear.compose.material3.ChildButton

androidx.wear.compose.material.CompactChip

androidx.wear.compose.material3.CompactButton

androidx.wear.compose.material.InlineSlider

androidx.wear.compose.material3.Slider

androidx.wear.compose.material.LocalContentAlpha

Zostało usunięte, ponieważ nie jest używane przez Text ani Icon w Material 3.

androidx.wear.compose.material.PositionIndicator

androidx.wear.compose.material3.ScrollIndicator

androidx.wear.compose.material.RadioButton

Brak odpowiednika w M3. Przejdź na androidx.wear.compose.material3.RadioButton lub androidx.wear.compose.material3.SplitRadioButton.

androidx.wear.compose.material.SwipeToRevealCard

androidx.wear.compose.material3.SwipeToReveal

androidx.wear.compose.material.SwipeToRevealChip

androidx.wear.compose.material3.SwipeToReveal

android.wear.compose.material.Scaffold

androidx.wear.compose.material3.AppScaffoldandroidx.wear.compose.material3.ScreenScaffold

androidx.wear.compose.material.SplitToggleChip

Brak odpowiednika w wersji 3.0. Przejdź na androidx.wear.compose.material3.SplitCheckboxButton, androidx.wear.compose.material3.SplitSwitchButton lub androidx.wear.compose.material3.SplitRadioButton.

androidx.wear.compose.material.Switch

Brak odpowiednika w M3. Przejdź na androidx.wear.compose.material3.SwitchButton lub androidx.wear.compose.material3.SplitSwitchButton.

androidx.wear.compose.material.ToggleButton

androidx.wear.compose.material3.IconToggleButton lub androidx.wear.compose.material3.TextToggleButton

androidx.wear.compose.material.ToggleChip

androidx.wear.compose.material3.CheckboxButton lub
androidx.wear.compose.material3.RadioButton lub
androidx.wear.compose.material3.SwitchButton

androidx.wear.compose.material.Vignette

Usunięto, ponieważ nie jest to część projektu Material 3 Expressive na Wear OS

Oto pełna lista wszystkich komponentów Material 3:

Materiał 3

Komponent odpowiadający Material 2.5 (jeśli nie jest nowy w M3)

androidx.wear.compose.material3.AlertDialog

androidx.wear.compose.material.dialog.Alert

androix.wear.compose.material3.AnimatedPage

Nowość

androidx.wear.compose.material3.AnimatedText

Nowość

androidx.wear.compose material3.AppScaffold

android.wear.compose.material.Scaffold (z androidx.wear.compose.material3.ScreenScaffold)

androidx.wear.compose.material3.Button

androidx.wear.compose.material.Chip

androidx.wear.compose.material3.ButtonGroup

Nowość

androidx.wear.compose.material3.Card

androidx.wear.compose.material.Card

androidx.wear.compose.material3.CheckboxButton

androidx.wear.compose.material.ToggleChip z polem wyboru

androidx.wear.compose.material3.ChildButton

androidx.wear.compose.material.Chip (tylko wtedy, gdy nie jest wymagane tło)

androidx.wear.compose.material3.CircularProgressIndicator

androidx.wear.compose.material.CircularProgressIndicator

androidx.wear.compose.material3.CompactButton

androidx.wear.compose.material.CompactChip

androidx.wear.compose.material3.ConfirmationDialog

androidx.wear.compose.material.dialog.Confirmation

androidx.wear.compose.material3.curvedText

androidx.wear.compose.material.curvedText

androidx.wear.compose.material3.DatePicker

Nowość

androidx.wear.compose.material3.Dialog

androidx.wear.compose.material.dialog.Dialog

androidx.wear.compose.material3.EdgeButton

Nowość

androidx.wear.compose.material3.FadingExpandingLabel

Nowość

androidx.wear.compose.material3.FilledTonalButton

androidx.wear.compose.material.Chip, gdy wymagane jest tło przycisku w tonalnym kolorze

androidx.wear.compose.material3.HorizontalPageIndicator

androidx.wear.compose.material.HorizontalPageIndicator

androidx.wear.compose.material3.HorizontalPagerScaffold

Nowość

androidx.wear.compose.material3.Icon

androidx.wear.compose.material.Icon

androidx.wear.compose.material3.IconButton

androidx.wear.compose.material.Button

androidx.wear.compose.material3.IconToggleButton

androidx.wear.compose.material.ToggleButton

androidx.wear.compose.material3.LevelIndicator

Nowość

androidx.wear.compose.material3.LinearProgressIndicator

Nowość

androidx.wear.compose.material3.ListHeader

androidx.wear.compose.material.ListHeader

androidx.wear.compose.material3.ListSubHeader

Nowość

androidx.wear.compose.material3.MaterialTheme

androidx.wear.compose.material.MaterialTheme

androidx.wear.compose.material3.OpenOnPhoneDialog

Nowość

androidx.wear.compose.material3.Picker

androidx.wear.compose.material.Picker

androidx.wear.compose.material3.PickerGroup

androidx.wear.compose.material.PickerGroup

androix.wear.compose.material3.RadioButton

androidx.wear.compose.material.ToggleChip z przełącznikiem opcji

androidx.wear.compose.material3.ScreenScaffold

android.wear.compose.material.Scaffold (z androidx.wear.compose.material3.AppScaffold)

androidx.wear.compose.material3.ScrollIndicator

androidx.wear.compose.material.PositionIndicator

androidx.wear.compose.material3.scrollaway

androidx.wear.compose.material.scrollaway

androidx.wear.compose.material3.SegmentedCircularProgressIndicator

Nowość

androidx.wear.compose.material3.Slider

androidx.wear.compose.material.InlineSlider

androidx.wear.compose.material3.SplitRadioButton

androidx.wear.compose.material.SplitToggleChip

androidx.wear.compose.material3.SplitCheckboxButton

androidx.wear.compose.material.SplitToggleChip

androidx.wear.compose.material3.SplitSwitchButton

androidx.wear.compose.material.SplitToggleChip

androidx.wear.compose.material3.Stepper

androidx.wear.compose.material.Stepper

androidx.wear.compose.material3.SwipeToDismissBox

androidx.wear.compose.material.SwipeToDismissBox

androidx.wear.compose.material3.SwipeToReveal

androidx.wear.compose.material.SwipeToRevealCardandroidx.wear.compose.material.SwipeToRevealChip

androidx.wear.compose.material3.SwitchButton

androidx.wear.compose.material.ToggleChip z przełącznikiem

androidx.wear.compose.material3.Text

androidx.wear.compose.material.Text

androidx.wear.compose.material3.TextButton

androidx.wear.compose.material.Button

androidx.wear.compose.material3.TextToggleButton

androidx.wear.compose.material.ToggleButton

androidx.wear.compose.material3.TimeText

androidx.wear.compose.material.TimeText

androidx.wear.compose.material3.VerticalPagerScaffold

Nowość

Na koniec lista niektórych odpowiednich komponentów z biblioteki Compose Foundation dla Wear w wersji 1.5.0-beta01:

Wear Compose Foundation 1.5.0-beta

androidx.wear.compose.foundation.hierarchicalFocusGroup

Służy do dodawania adnotacji do komponentów w aplikacji, aby śledzić aktywną część kompozycji i koordynować ostrość.

androidx.compose.foundation.pager.HorizontalPager

Przewijany poziomo pager oparty na komponentach Compose Foundation z ulepszeniami dotyczącymi Wear, które zwiększają wydajność i zgodność z wytycznymi dla Wear OS.

androidx.compose.foundation.pager.VerticalPager

Przewijany pionowo pager oparty na komponentach Compose Foundation z ulepszeniami dotyczącymi Wear, które zwiększają wydajność i zgodność z wytycznymi dla Wear OS.

androidx.wear.foundation.lazy.TransformingLazyColumn

Można go używać zamiast ScalingLazyColumn, aby dodać do każdego elementu efekty przekształcania podczas przewijania.

Przyciski

Przyciski w M3 różnią się od tych w M2.5. Element M2.5 Chip został zastąpiony przez przycisk. Implementacja Button udostępnia wartości domyślne dla Text, maxLinestextAlign. Te wartości domyślne można zastąpić w elemencie Text.

M2,5

import androidx.wear.compose.material.Chip

//M2.5 Buttons
Chip(...)
CompactChip(...)
Button(...)

M3

import androidx.wear.compose.material3.Button

//M3 Buttons
Button(...)
CompactButton(...)
IconButton(...)
TextButton(...)

M3 zawiera też nowe warianty przycisków. Znajdziesz je w omówieniu interfejsu API Compose Material 3.

W M3 wprowadzono nowy przycisk: EdgeButton. EdgeButton jest dostępny w 4 różnych rozmiarach: bardzo mały, mały, średni i duży. Implementacja EdgeButton udostępnia domyślną wartość dla maxLines w zależności od rozmiaru, który można dostosować.

Jeśli używasz elementów TransformingLazyColumnScalingLazyColumn, prześlij element EdgeButton do elementu ScreenScaffold, aby mógł się przekształcać i zmieniać kształt podczas przewijania. W poniższym kodzie możesz sprawdzić, jak używać funkcji EdgeButton w połączeniu z funkcjami ScreenScaffoldTransformingLazyColumn.

import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.ScreenScaffold

ScreenScaffold(
   scrollState = state,
   contentPadding = contentPadding,
   edgeButton = {
      EdgeButton(...)
   }
){ contentPadding ->
   TransformingLazyColumn(state = state, contentPadding = contentPadding,){
   // additional code here
   }
}

Rusztowanie

Szkielet w M3 różni się od tego w M2.5. W M3 moduł AppScaffold i nowy moduł ScreenScaffold zastąpiły moduł Scaffold. AppScaffoldScreenScaffold określają strukturę ekranu oraz koordynują przejścia między komponentami ScrollIndicatorTimeText.

AppScaffold pozwala zachować widoczność statycznych elementów ekranu, takich jak TimeText, podczas przejść w aplikacji, np. podczas przesuwania w bok, aby zamknąć. ​​Oferuje on slot na główną treść aplikacji, która jest zwykle dostarczana przez element nawigacji, taki jak SwipeDismissableNavHost

Deklarujesz 1 element AppScaffold dla aktywności i używasz ScreenScaffold dla każdego ekranu.

M2,5

import androidx.wear.compose.material.Scaffold

Scaffold {...}

M3

import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.ScreenScaffold

AppScaffold {
   // Define the navigation hierarchy within the AppScaffold,
   // such as using SwipeDismissableNavHost.
   SwipeDismissableNavHost(...) {
      composable("home") {
         HomeScreen()
      }
      //other screens
   }
}
fun HomeScreen() {
    val scrollState = rememberScrollState()
    ScreenScaffold(scrollState = scrollState) {
    //rest of the screen code
    }
}

Jeśli używasz HorizontalPagerHorizontalPagerIndicator, możesz przejść na HorizontalPagerScaffold. HorizontalPagerScaffold jest umieszczony w AppScaffold. AppScaffoldHorizontalPagerScaffold określają strukturę strony Pager, a także koordynują przejścia między komponentami HorizontalPageIndicatorTimeText.

HorizontalPagerScaffold domyślnie wyświetla HorizontalPageIndicator na środku ekranu oraz koordynuje wyświetlanie/ukrywanie TimeText i HorizontalPageIndicator w zależności od tego, czy Pager jest przewijany. Jest to określane przez PagerState.

Dostępny jest też nowy komponent AnimatedPage, który animuje stronę w przeglądarce z efektem skalowania i zaciemnienia zależnego od jej położenia.

import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.HorizontalPagerScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.foundation.pager.HorizontalPager
import androidx.wear.compose.foundation.pager.rememberPagerState

AppScaffold {
    val pagerState = rememberPagerState(pageCount = { 10 })

    HorizontalPagerScaffold(pagerState = pagerState) {
       HorizontalPager(
          state = pagerState,
        ) { page ->
            AnimatedPage(pageIndex = page, pagerState = pagerState) {
                ScreenScaffold {

   }
}

W M3 wprowadzamy też VerticalPagerScaffold, który działa według tego samego wzorca co HorizontalPagerScaffold:

import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.HorizontalPagerScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.foundation.pager.VerticalPager
import androidx.wear.compose.foundation.pager.rememberPagerState

AppScaffold {
   val pagerState = rememberPagerState(pageCount = { 10 })

   VerticalPagerScaffold(pagerState = pagerState) {
      VerticalPager(
         state = pagerState
      ) { page ->
             AnimatedPage(pageIndex = page, pagerState = pagerState){
                ScreenScaffold {
        
   }
}

Obiekt zastępczy

Między wersjami M2.5 a M3 wprowadzono pewne zmiany w interfejsie API. Placeholder.PlaceholderDefaults obsługuje teraz 2 modyfikatory:

  • Modifier.placeholder, który jest wyświetlany zamiast treści, które nie zostały jeszcze załadowane.
  • Efekt migotania zastępczego Modifier.placeholderShimmer, który zapewnia efekt migotania zastępczego, który działa w pętli animacji podczas oczekiwania na załadowanie danych.

Poniżej znajdziesz dodatkowe informacje o komponencie Placeholder.

M2,5

M3

PlaceholderState.startPlaceholderAnimation

został usunięty.

PlaceholderState.placeholderProgression

został usunięty.

PlaceholderState.isShowContent

Nazwa została zmieniona na !PlaceholderState.isVisible

PlaceholderState.isWipeOff

został usunięty.

PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush

został usunięty.

PlaceholderDefaults.placeholderBackgroundBrush

został usunięty.

PlaceholderDefaults.placeholderChipColors

został usunięty.

SwipeDismissableNavHost

SwipeDismissableNavHost należy do wear.compose.navigation. Gdy ten komponent jest używany z M3, motyw MaterialTheme M3 aktualizuje elementy LocalSwipeToDismissBackgroundScrimColorLocalSwipeToDismissContentScrimColor.

TransformingLazyColumn

TransformingLazyColumn jest częścią wear.compose.lazy.foundation i dodaje obsługę animacji skalowania i przekształcania elementów listy podczas przewijania, co zwiększa wygodę użytkowników.

Podobnie jak w przypadku ScalingLazyColumn, umożliwia ona rememberTransformingLazyColumnState() tworzenie TransformingLazyColumnState, które jest zapamiętywane w różnych kompozycjach.

Aby dodać animacje skalowania i przekształcania, dodaj do każdego elementu listy te elementy:

  • Modifier.transformedHeight, która umożliwia obliczenie przekształconej wysokości elementów za pomocą funkcji TransformationSpec. Możesz użyć funkcji rememberTransformationSpec(), chyba że potrzebujesz dalszej personalizacji.
  • SurfaceTransformation
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.SurfaceTransformation
import androidx.wear.compose.material3.lazy.rememberTransformationSpec
import androidx.wear.compose.material3.lazy.transformedHeight
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn

val state = rememberTransformingLazyColumnState()
val transformationSpec = rememberTransformationSpec()
AppScaffold {
   ScreenScaffold(state) { contentPadding ->
      TransformingLazyColumn(state = state, contentPadding = contentPadding) {
         items(count = 50) {
            Button(
               onClick = {},
               modifier =
                        Modifier.fillMaxWidth().transformedHeight(this, transformationSpec),
                        transformation = SurfaceTransformation(transformationSpec),
                    ) {
                        Text("Item $it")
                    }
                }
            }
        }
    }

Przydatne linki

Więcej informacji o przechodzeniu z wersji M2.5 na M3 w Compose znajdziesz w tych dodatkowych materiałach.

Próbki

Przykłady kodu Wear OS w gałęzi Material3 na GitHubie

Tworzenie aplikacji na Wear OS – ćwiczenie z Codelab

Dokumentacja i kod źródłowy interfejsu API

Projektowanie