diff --git a/android/app/build.gradle b/android/app/build.gradle index 8985cc10..b4fe0a56 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,7 +91,7 @@ android { applicationId 'app.neuland' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 230 + versionCode 231 versionName "0.11.0" } signingConfigs { diff --git a/app.config.json b/app.config.json index f31fe56a..4e2ad10d 100644 --- a/app.config.json +++ b/app.config.json @@ -36,7 +36,7 @@ "android": { "package": "app.neuland", "userInterfaceStyle": "automatic", - "versionCode": 230 + "versionCode": 231 }, "sdkVersion": "52.0.0", "experiments": { diff --git a/bun.lockb b/bun.lockb index c4cfcbc6..cb7c1603 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3c90277d..a25d19a0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -233,6 +233,8 @@ PODS: - ExpoModulesCore - ExpoClipboard (7.0.0): - ExpoModulesCore + - ExpoCrypto (14.0.1): + - ExpoModulesCore - ExpoFileSystem (18.0.4): - ExpoModulesCore - ExpoFont (13.0.1): @@ -2295,6 +2297,7 @@ DEPENDENCIES: - ExpoBlur (from `../node_modules/expo-blur/ios`) - ExpoBrightness (from `../node_modules/expo-brightness/ios`) - ExpoClipboard (from `../node_modules/expo-clipboard/ios`) + - ExpoCrypto (from `../node_modules/expo-crypto/ios`) - ExpoFileSystem (from `../node_modules/expo-file-system/ios`) - ExpoFont (from `../node_modules/expo-font/ios`) - ExpoHaptics (from `../node_modules/expo-haptics/ios`) @@ -2438,6 +2441,8 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-brightness/ios" ExpoClipboard: :path: "../node_modules/expo-clipboard/ios" + ExpoCrypto: + :path: "../node_modules/expo-crypto/ios" ExpoFileSystem: :path: "../node_modules/expo-file-system/ios" ExpoFont: @@ -2651,6 +2656,7 @@ SPEC CHECKSUMS: ExpoBlur: 562b3da84d3cd79016c411671eaf71a404266415 ExpoBrightness: ce777f6a365592f745428cb0acc9066b400182e8 ExpoClipboard: 166ca8c13ca1041f5ba619a211f59427ab5da8a7 + ExpoCrypto: 8465f71eb3798c194c0a509d4a76e5c429656d83 ExpoFileSystem: dc2679a2b5d4c465ca881129074da95faee943d5 ExpoFont: 7522d869d84ee2ee8093ee997fef5b86f85d856b ExpoHaptics: e636188d1d5f7ccb79f3c1bfab47aaf5a1768c73 diff --git a/package.json b/package.json index 3429586d..4d68e291 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "expo-build-properties": "~0.13.1", "expo-clipboard": "~7.0.0", "expo-constants": "~17.0.3", + "expo-crypto": "~14.0.1", "expo-haptics": "~14.0.0", "expo-linear-gradient": "~14.0.1", "expo-local-authentication": "~15.0.1", @@ -80,6 +81,7 @@ "react-native-pager-view": "6.5.1", "react-native-paper": "5.12.5", "react-native-reanimated": "~3.16.3", + "react-native-reanimated-carousel": "^3.5.1", "react-native-safe-area-context": "4.12.0", "react-native-screens": "~4.1.0", "react-native-select-dropdown": "^4.0.1", diff --git a/src/components/Cards/NewsCard.tsx b/src/components/Cards/NewsCard.tsx new file mode 100644 index 00000000..a3329a04 --- /dev/null +++ b/src/components/Cards/NewsCard.tsx @@ -0,0 +1,129 @@ +import API from '@/api/authenticated-api' +import { UserKindContext } from '@/components/contexts' +import { USER_GUEST } from '@/data/constants' +import { type ThiNews } from '@/types/thi-api' +import { useQuery } from '@tanstack/react-query' +import React, { useContext, useLayoutEffect, useRef } from 'react' +import { useTranslation } from 'react-i18next' +import { Dimensions, Image, Linking, Pressable, Text, View } from 'react-native' +import Carousel from 'react-native-reanimated-carousel' +import { createStyleSheet, useStyles } from 'react-native-unistyles' + +import BaseCard from './BaseCard' + +const NewsCard: React.FC = () => { + const ref = useRef(null) + const { t } = useTranslation('navigation') + const { styles } = useStyles(stylesheet) + const { userKind = USER_GUEST } = useContext(UserKindContext) + const { data } = useQuery({ + queryKey: ['thiNews'], + queryFn: async () => await API.getThiNews(), + staleTime: 1000 * 60 * 10, // 10 minutes + gcTime: 1000 * 60 * 60 * 24, // 24 hours + enabled: userKind !== USER_GUEST, + }) + const [cardWidth, setCardWidth] = React.useState( + Dimensions.get('window').width - 32 + ) + useLayoutEffect(() => { + if (ref.current != null) { + // @ts-expect-error unstable_getBoundingClientRect is not in the types + const width = ref.current.unstable_getBoundingClientRect() + .width as number + setCardWidth(width) + } + }, []) + + const renderEvent = (event: ThiNews): JSX.Element => { + return ( + { + void Linking.openURL(event.href) + }} + > + + + {event.title} + + + ) + } + + return ( + + + {data != null && data.length > 0 && ( + ( + + {renderEvent(data[index])} + + )} + > + )} + {data != null && data.length > 2 && ( + + + {t('cards.news.more', { + count: data.length, + })} + + + )} + + + ) +} + +const stylesheet = createStyleSheet((theme) => ({ + cardsFilled: { gap: 8, paddingTop: 12 }, + carousel: { + alignItems: 'center', + justifyContent: 'center', + marginTop: 4, + width: '100%', + }, + description: { + color: theme.colors.labelColor, + fontSize: 14, + fontWeight: '500', + }, + eventContainer: { + alignItems: 'center', + backgroundColor: theme.colors.cardButton, + borderRadius: theme.radius.md, + flexDirection: 'row', + gap: 12, + marginHorizontal: 4, + padding: 10, + }, + eventTitle: { + color: theme.colors.text, + flexShrink: 1, + fontSize: 15, + fontWeight: '500', + }, + imageContainer: { + borderRadius: theme.radius.sm, + height: 80, + resizeMode: 'cover', + width: '35%', + }, +})) + +export default NewsCard diff --git a/src/components/Map/MapScreen.tsx b/src/components/Map/MapScreen.tsx index 1378b932..e2cc41c8 100644 --- a/src/components/Map/MapScreen.tsx +++ b/src/components/Map/MapScreen.tsx @@ -888,7 +888,11 @@ const MapScreen = (): JSX.Element => { }} style={layerStyles.osmBackground} > - + {'© OpenStreetMap'} diff --git a/src/components/allCards.tsx b/src/components/allCards.tsx index 07453e7d..84334d79 100644 --- a/src/components/allCards.tsx +++ b/src/components/allCards.tsx @@ -11,6 +11,7 @@ import { TimetableCard, } from './Cards' import LibraryCard from './Cards/LibraryCard' +import NewsCard from './Cards/NewsCard' export const AllCards: Card[] = [ { @@ -62,7 +63,7 @@ export const AllCards: Card[] = [ removable: true, initial: [USER_STUDENT, USER_EMPLOYEE], allowed: [USER_STUDENT, USER_EMPLOYEE], - card: () => , + card: () => , }, { key: 'lecturers', diff --git a/src/data/licenses.json b/src/data/licenses.json index f498f081..ac9ed0c5 100644 --- a/src/data/licenses.json +++ b/src/data/licenses.json @@ -143,6 +143,12 @@ "licenseUrl": "https://github.com/expo/expo", "parents": "neuland" }, + "expo-crypto@14.0.1": { + "licenses": "MIT", + "repository": "https://github.com/expo/expo", + "licenseUrl": "https://github.com/expo/expo", + "parents": "neuland" + }, "expo-haptics@14.0.0": { "licenses": "MIT", "repository": "https://github.com/expo/expo", @@ -191,7 +197,7 @@ "licenseUrl": "https://github.com/expo/expo", "parents": "neuland" }, - "expo-splash-screen@0.29.13": { + "expo-splash-screen@0.29.16": { "licenses": "MIT", "repository": "https://github.com/expo/expo", "licenseUrl": "https://github.com/expo/expo", @@ -203,7 +209,7 @@ "licenseUrl": "https://github.com/expo/expo", "parents": "neuland" }, - "expo@52.0.15": { + "expo@52.0.17": { "licenses": "MIT", "repository": "https://github.com/expo/expo", "licenseUrl": "https://github.com/expo/expo", @@ -215,12 +221,6 @@ "licenseUrl": "https://github.com/krisk/Fuse/raw/master/LICENSE", "parents": "neuland" }, - "graphql-request@7.1.2": { - "licenses": "MIT", - "repository": "https://github.com/jasonkuhrt/graphql-request", - "licenseUrl": "https://github.com/jasonkuhrt/graphql-request/raw/master/LICENSE", - "parents": "neuland" - }, "graphql@16.9.0": { "licenses": "MIT", "repository": "https://github.com/graphql/graphql-js", @@ -329,6 +329,12 @@ "licenseUrl": "https://github.com/callstack/react-native-paper/raw/master/LICENSE.md", "parents": "neuland" }, + "react-native-reanimated-carousel@3.5.1": { + "licenses": "MIT", + "repository": "https://github.com/dohooo/react-native-reanimated-carousel", + "licenseUrl": "https://github.com/dohooo/react-native-reanimated-carousel/raw/master/LICENSE", + "parents": "neuland" + }, "react-native-reanimated@3.16.3": { "licenses": "MIT", "repository": "https://github.com/software-mansion/react-native-reanimated", diff --git a/src/localization/de/navigation.json b/src/localization/de/navigation.json index f5c503e3..6c73ef26 100644 --- a/src/localization/de/navigation.json +++ b/src/localization/de/navigation.json @@ -62,6 +62,9 @@ "events": { "by": "von {{name}}" }, + "news": { + "more": "Lese alle {{count}} Artikel" + }, "calendar": { "exam": "Prüfung: {{name}}", "ends": "endet " diff --git a/src/localization/en/navigation.json b/src/localization/en/navigation.json index e558c365..d6b8a92c 100644 --- a/src/localization/en/navigation.json +++ b/src/localization/en/navigation.json @@ -62,6 +62,9 @@ "events": { "by": "by {{name}}" }, + "news": { + "more": "Read all {{count}} articles" + }, "calendar": { "exam": "Exam: {{name}}", "ends": "ends "