From f2ecc1803f3ea294a0c6b7915b61348ed0395b26 Mon Sep 17 00:00:00 2001 From: Marcin Zelent Date: Wed, 16 Nov 2022 15:16:38 +0100 Subject: Remade and extended the app using React --- src/models/Group.ts | 35 ++++++++++++++++++++++++++++ src/models/MediaItem.ts | 53 +++++++++++++++++++++++++++++++++++++++++++ src/models/MediaType.ts | 6 +++++ src/models/Trip.ts | 28 +++++++++++++++++++++++ src/models/index.guard.ts | 58 +++++++++++++++++++++++++++++++++++++++++++++++ src/models/index.ts | 7 ++++++ 6 files changed, 187 insertions(+) create mode 100644 src/models/Group.ts create mode 100644 src/models/MediaItem.ts create mode 100644 src/models/MediaType.ts create mode 100644 src/models/Trip.ts create mode 100644 src/models/index.guard.ts create mode 100644 src/models/index.ts (limited to 'src/models') diff --git a/src/models/Group.ts b/src/models/Group.ts new file mode 100644 index 0000000..9b3aa6d --- /dev/null +++ b/src/models/Group.ts @@ -0,0 +1,35 @@ +import { FeatureCollection } from 'geojson'; +import MediaItem from './MediaItem'; + +export default interface Group { + /** + * ID of the group used in URLs. + */ + id: string; + + /** + * Name of the group. + */ + name?: string; + + /** + * Description of the group. + */ + + description?: string; + + /** + * Medias in the group. + */ + media: MediaItem[]; + + /** + * Geo data track info in GeoJSON format. + */ + geoData?: FeatureCollection[]; + + /** + * Metadata that can be displayed in the description. + */ + metadata?: { [key: string]: string | number }; +} diff --git a/src/models/MediaItem.ts b/src/models/MediaItem.ts new file mode 100644 index 0000000..de1410a --- /dev/null +++ b/src/models/MediaItem.ts @@ -0,0 +1,53 @@ +import MediaType from "./MediaType"; + +export default interface MediaItem { + /** + * Name of the media item or the file. + */ + name: string; + + /** + * Path to the media item. + */ + src: string; + + /** + * Type of the media item. Can be a "photo" or a "video". + */ + type: MediaType; + + /** + * Width of the media item in pixels. + */ + width: number; + + /** + * Height of the media item in pixels. + */ + height: number; + + /** + * Latitude where the media item was taken. + */ + latitude?: number; + + /** + * Logitude where the media item was taken. + */ + longitude?: number; + + /** + * Date and time when the media item was taken. + */ + time?: string; + + /** + * Media item thumbnail. + */ + thumbnail?: string; + + /** + * Caption on the media item. + */ + caption?: string; +} diff --git a/src/models/MediaType.ts b/src/models/MediaType.ts new file mode 100644 index 0000000..74bb933 --- /dev/null +++ b/src/models/MediaType.ts @@ -0,0 +1,6 @@ +enum MediaType { + Photo = "photo", + Video = "video", +} + +export default MediaType; diff --git a/src/models/Trip.ts b/src/models/Trip.ts new file mode 100644 index 0000000..7f92669 --- /dev/null +++ b/src/models/Trip.ts @@ -0,0 +1,28 @@ +import Group from './Group'; + +export default interface Trip { + /** + * ID of the trip, used internally within the application. + */ + id: string; + + /** + * Name of the trip, displayed to the user. + */ + name: string; + + /** + * Groups the trip is split into. + */ + groups?: Group[]; + + /** + * URL to a JSON file containing data for the trip. + */ + url: string; + + /** + * Property indicating if the trip data has been already downloaded. + */ + downloaded: boolean; +} diff --git a/src/models/index.guard.ts b/src/models/index.guard.ts new file mode 100644 index 0000000..d564ff9 --- /dev/null +++ b/src/models/index.guard.ts @@ -0,0 +1,58 @@ +import { Trip, Group, MediaItem } from './index'; + +export function isGroup(obj: unknown): obj is Group { + const typedObj = obj as Group; + const isValid = + ((typedObj !== null && typeof typedObj === 'object') || typeof typedObj === 'function') && + typeof typedObj.id === 'string' && + (typeof typedObj.name === 'undefined' || typeof typedObj.name === 'string') && + (typeof typedObj.description === 'undefined' || typeof typedObj.description === 'string') && + Array.isArray(typedObj.media) && + typedObj.media.every((e: any) => isMediaItem(e)); + + if (!isValid) { + throw new Error(`Invalid object: ${JSON.stringify(obj)}`); + } + + return isValid; +} + +export function isMediaItem(obj: unknown): obj is MediaItem { + const typedObj = obj as MediaItem; + const isValid = + ((typedObj !== null && typeof typedObj === 'object') || typeof typedObj === 'function') && + typeof typedObj.name === 'string' && + typeof typedObj.src === 'string' && + typeof typedObj.type === 'string' && + (typedObj.type === 'photo' || typedObj.type === 'video') && + typeof typedObj.width === 'number' && + typeof typedObj.height === 'number' && + (typeof typedObj.latitude === 'number' || typeof typedObj.latitude === 'undefined') && + (typeof typedObj.longitude === 'number' || typeof typedObj.longitude === 'undefined') && + (typeof typedObj.time === 'undefined' || typeof typedObj.time === 'string') && + (typeof typedObj.thumbnail === 'string' || typeof typedObj.thumbnail === 'undefined') && + (typeof typedObj.caption === 'undefined' || typeof typedObj.caption === 'string'); + + if (!isValid) { + throw new Error(`Invalid object: ${JSON.stringify(obj)}`); + } + + return isValid; +} + +export function isTrip(obj: unknown): obj is Trip { + const typedObj = obj as Trip; + const isValid = + ((typedObj !== null && typeof typedObj === 'object') || typeof typedObj === 'function') && + typeof typedObj.id === 'string' && + typeof typedObj.name === 'string' && + (typeof typedObj.groups === 'undefined' || + (Array.isArray(typedObj.groups) && typedObj.groups.every((e: any) => isGroup(e))) + ); + + if (!isValid) { + throw new Error(`Invalid object: ${JSON.stringify(obj)}`); + } + + return isValid; +} diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..506de25 --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,7 @@ +import Group from './Group'; +import MediaItem from './MediaItem'; +import MediaType from './MediaType'; +import Trip from './Trip'; + +export type { Group, MediaItem, Trip }; +export { MediaType }; -- cgit v1.2.3