diff --git a/app/(app)/(authorized)/(tabs)/example/skia-components.tsx b/app/(app)/(authorized)/(tabs)/example/skia-components.tsx
new file mode 100644
index 00000000..0a4ef082
--- /dev/null
+++ b/app/(app)/(authorized)/(tabs)/example/skia-components.tsx
@@ -0,0 +1,3 @@
+import { SkiaComponentsScreen } from '@baca/screens'
+
+export default SkiaComponentsScreen
diff --git a/package.json b/package.json
index 0a76f229..8f378d2a 100644
--- a/package.json
+++ b/package.json
@@ -106,6 +106,7 @@
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.17",
"@react-navigation/stack": "^6.3.20",
+ "@shopify/react-native-skia": "^1.3.6",
"@tanstack/react-query": "^4.29.19",
"axios": "^1.7.2",
"core-js": "^3.37.1",
diff --git a/src/components/skia/ProgressBar.tsx b/src/components/skia/ProgressBar.tsx
new file mode 100644
index 00000000..7a2210f1
--- /dev/null
+++ b/src/components/skia/ProgressBar.tsx
@@ -0,0 +1,78 @@
+import {
+ Canvas,
+ LinearGradient,
+ Path,
+ Skia,
+ Text,
+ useFont,
+ useTouchHandler,
+ vec,
+} from '@shopify/react-native-skia'
+import { useEffect } from 'react'
+import { useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated'
+
+type ProgressBarProps = {
+ initialProgress: number
+ height?: number
+ width?: number
+}
+
+const FONT_SIZE = 24
+
+export const ProgressBar = ({ height = 32, initialProgress, width = 200 }: ProgressBarProps) => {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const font = useFont(require('@baca/assets/fonts/Inter-Bold.ttf'), FONT_SIZE)
+
+ const path = Skia.Path.Make()
+ path.moveTo(0, height / 2)
+ path.lineTo(width, height / 2)
+
+ const progress = useSharedValue(0)
+
+ useEffect(() => {
+ progress.value = withTiming(initialProgress / 100, { duration: 1000 })
+ }, [initialProgress])
+
+ const onTouch = useTouchHandler({
+ onStart: ({ x }) => setNewProgress(x),
+ onActive: ({ x }) => setNewProgress(x),
+ })
+
+ const setNewProgress = (x: number) => {
+ let newProgress
+ if (x >= width) {
+ newProgress = 1
+ } else if (x <= 0) {
+ newProgress = 0
+ } else {
+ newProgress = x / width
+ }
+ progress.value = newProgress
+ }
+
+ const text = useDerivedValue(() => `${Math.floor(progress.value * 100)}%`)
+
+ const textX = useDerivedValue(() => {
+ const size = font?.measureText(text.value)?.width
+
+ return width / 2 - size! / 2
+ })
+
+ return (
+ <>
+
+
+ >
+ )
+}
diff --git a/src/i18n/translations/en.json b/src/i18n/translations/en.json
index 26a6c44a..ddbf45aa 100644
--- a/src/i18n/translations/en.json
+++ b/src/i18n/translations/en.json
@@ -188,6 +188,7 @@
"go_to_screen_test_form": "Go to test form",
"go_to_screen_with_BEdata": "Go to screen with data from BE",
"go_to_settings": "Go to Settings",
+ "go_to_skia_components": "Go to skia components",
"go_to_typography": "Go to Typography",
"go_to_user_session": "Go to user session",
"header": "This is Example screen"
diff --git a/src/i18n/translations/pl.json b/src/i18n/translations/pl.json
index c9ebd6af..c8e0aa10 100644
--- a/src/i18n/translations/pl.json
+++ b/src/i18n/translations/pl.json
@@ -188,6 +188,7 @@
"go_to_screen_test_form": "Idź do formularza testowego",
"go_to_screen_with_BEdata": "Idź do widoku z danymi z backend-u",
"go_to_settings": "Idź do Ustawień",
+ "go_to_skia_components": "Idź do Komponentów Skia",
"go_to_typography": "Idź do Typografii",
"go_to_user_session": "Idź do sesji użytkowania",
"header": "To jest przykładowy widok"
diff --git a/src/screens/ExamplesScreen.tsx b/src/screens/ExamplesScreen.tsx
index caba6d66..c7a49efd 100644
--- a/src/screens/ExamplesScreen.tsx
+++ b/src/screens/ExamplesScreen.tsx
@@ -24,6 +24,8 @@ export const ExamplesScreen = () => {
const goToHomeStackDetails = useCallback(() => push('/home/details'), [push])
+ const goToSkiaComponents = useCallback(() => push('/example/skia-components'), [push])
+
return (
)
}
diff --git a/src/screens/SkiaComponentsScreen.tsx b/src/screens/SkiaComponentsScreen.tsx
new file mode 100644
index 00000000..0da93509
--- /dev/null
+++ b/src/screens/SkiaComponentsScreen.tsx
@@ -0,0 +1,18 @@
+import { ProgressBar } from '@baca/components/skia/ProgressBar'
+import { StyleSheet, View } from 'react-native'
+
+export const SkiaComponentsScreen = (): JSX.Element => {
+ return (
+
+
+
+ )
+}
+
+const style = StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ flex: 1,
+ justifyContent: 'center',
+ },
+})
diff --git a/src/screens/index.ts b/src/screens/index.ts
index 8eff38bd..694e3893 100644
--- a/src/screens/index.ts
+++ b/src/screens/index.ts
@@ -12,6 +12,7 @@ export * from './NotFoundScreen'
export * from './ProfileScreen'
export * from './PushNotificationsHelpersScreen'
export * from './SettingsScreen'
+export * from './SkiaComponentsScreen'
export * from './TestFormScreen'
export * from './TypographyScreen'
export * from './UserSessionScreen'
diff --git a/yarn.lock b/yarn.lock
index 6f9b7985..1bfc1b20 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2645,6 +2645,14 @@
component-type "^1.2.1"
join-component "^1.1.0"
+"@shopify/react-native-skia@^1.3.6":
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/@shopify/react-native-skia/-/react-native-skia-1.3.6.tgz#074c419e87a1bfb65310b3ebfa74a342c2a07e06"
+ integrity sha512-AT+yxt0UiAakcqUzbaLCL4kj/9cDlerhuUw2z/U+K7xeudLcox6mbLse98i9E+fUdIctxNFa50ltCo+9hQOPkg==
+ dependencies:
+ canvaskit-wasm "0.39.1"
+ react-reconciler "0.27.0"
+
"@sideway/address@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5"
@@ -3625,6 +3633,11 @@
"@webassemblyjs/ast" "1.12.1"
"@xtuc/long" "4.2.2"
+"@webgpu/types@0.1.21":
+ version "0.1.21"
+ resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.21.tgz#b181202daec30d66ccd67264de23814cfd176d3a"
+ integrity sha512-pUrWq3V5PiSGFLeLxoGqReTZmiiXwY3jRkIG5sLLKjyqNxrwm/04b4nw7LSmGWJcKk59XOM/YRTUwOzo4MMlow==
+
"@welldone-software/why-did-you-render@^7.0.1":
version "7.0.1"
resolved "https://registry.yarnpkg.com/@welldone-software/why-did-you-render/-/why-did-you-render-7.0.1.tgz#09f487d84844bd8e66435843c2e0305702e61efb"
@@ -4530,6 +4543,13 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz#4adcb443c8b9c8303e04498318f987616b8fea2e"
integrity sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA==
+canvaskit-wasm@0.39.1:
+ version "0.39.1"
+ resolved "https://registry.yarnpkg.com/canvaskit-wasm/-/canvaskit-wasm-0.39.1.tgz#c3c8f3962cbabbedf246f7bcf90e859013c7eae9"
+ integrity sha512-Gy3lCmhUdKq+8bvDrs9t8+qf7RvcjuQn+we7vTVVyqgOVO1UVfHpsnBxkTZw+R4ApEJ3D5fKySl9TU11hmjl/A==
+ dependencies:
+ "@webgpu/types" "0.1.21"
+
chalk@5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
@@ -11125,6 +11145,14 @@ react-native@0.74.1:
ws "^6.2.2"
yargs "^17.6.2"
+react-reconciler@0.27.0:
+ version "0.27.0"
+ resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.27.0.tgz#360124fdf2d76447c7491ee5f0e04503ed9acf5b"
+ integrity sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==
+ dependencies:
+ loose-envify "^1.1.0"
+ scheduler "^0.21.0"
+
react-refresh@^0.14.0, react-refresh@^0.14.2:
version "0.14.2"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9"
@@ -11584,6 +11612,13 @@ scheduler@0.24.0-canary-efb381bbf-20230505:
dependencies:
loose-envify "^1.1.0"
+scheduler@^0.21.0:
+ version "0.21.0"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0.tgz#6fd2532ff5a6d877b6edb12f00d8ab7e8f308820"
+ integrity sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==
+ dependencies:
+ loose-envify "^1.1.0"
+
scheduler@^0.23.0, scheduler@^0.23.2:
version "0.23.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"