From 95771a4b13e37b777bd7907db57f99e633b6213a Mon Sep 17 00:00:00 2001 From: ImJustChew Date: Tue, 16 Apr 2024 00:29:48 +0800 Subject: [PATCH] feat: added device specific download methods --- android/app/capacitor.build.gradle | 3 + android/app/src/main/AndroidManifest.xml | 3 +- android/capacitor.settings.gradle | 9 +++ capacitor.config.ts | 4 +- ios/App/Podfile | 3 + package-lock.json | 27 ++++++++ package.json | 3 + .../Timetable/DownloadTimetableDialog.tsx | 61 +++++++++++++++---- 8 files changed, 99 insertions(+), 14 deletions(-) diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index 1c2a7a88..1e1fa68a 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -9,7 +9,10 @@ android { apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" dependencies { + implementation project(':capacitor-community-media') implementation project(':capacitor-app') + implementation project(':capacitor-device') + implementation project(':capacitor-filesystem') implementation project(':capacitor-haptics') implementation project(':capacitor-keyboard') implementation project(':capacitor-status-bar') diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ad421fd0..c3607e6e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -30,6 +30,7 @@ - + + diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index bd358734..63201aa9 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -2,9 +2,18 @@ include ':capacitor-android' project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') +include ':capacitor-community-media' +project(':capacitor-community-media').projectDir = new File('../node_modules/@capacitor-community/media/android') + include ':capacitor-app' project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') +include ':capacitor-device' +project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android') + +include ':capacitor-filesystem' +project(':capacitor-filesystem').projectDir = new File('../node_modules/@capacitor/filesystem/android') + include ':capacitor-haptics' project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android') diff --git a/capacitor.config.ts b/capacitor.config.ts index f525905f..5b141e93 100644 --- a/capacitor.config.ts +++ b/capacitor.config.ts @@ -5,8 +5,8 @@ const config: CapacitorConfig = { appName: 'NTHUMods', webDir: 'fakeout', server: { - url: 'https://nthumods.com', - androidScheme: 'https', + url: process.env.NODE_ENV === 'production' ? 'https://nthumods.com' : 'http://192.168.31.109:3000', + androidScheme: process.env.NODE_ENV === 'production' ? 'https' : 'http', }, }; diff --git a/ios/App/Podfile b/ios/App/Podfile index aa46f1e8..cbfb5ae5 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -11,7 +11,10 @@ install! 'cocoapods', :disable_input_output_paths => true def capacitor_pods pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' + pod 'CapacitorCommunityMedia', :path => '../../node_modules/@capacitor-community/media' pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' + pod 'CapacitorDevice', :path => '../../node_modules/@capacitor/device' + pod 'CapacitorFilesystem', :path => '../../node_modules/@capacitor/filesystem' pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics' pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard' pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar' diff --git a/package-lock.json b/package-lock.json index c112ac14..b5cb9d6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,13 @@ "name": "courseweb", "version": "0.1.0", "dependencies": { + "@capacitor-community/media": "^5.4.1", "@capacitor/android": "^5.6.0", "@capacitor/app": "5.0.7", "@capacitor/cli": "5.6.0", "@capacitor/core": "5.6.0", + "@capacitor/device": "^5.0.7", + "@capacitor/filesystem": "^5.2.1", "@capacitor/haptics": "5.0.7", "@capacitor/ios": "5.6.0", "@capacitor/keyboard": "5.0.8", @@ -1639,6 +1642,14 @@ "node": ">=6.9.0" } }, + "node_modules/@capacitor-community/media": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@capacitor-community/media/-/media-5.4.1.tgz", + "integrity": "sha512-8Pf3MDGZ3B4U5Qs+TpkFlwmOu2gHVJjdEK32mTY2vF1shwptHK4Ixe30OU8cf1vDY/ye+LkZntcdHkTcfBjIgA==", + "peerDependencies": { + "@capacitor/core": "^5.0.0" + } + }, "node_modules/@capacitor/android": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.6.0.tgz", @@ -1801,6 +1812,22 @@ "tslib": "^2.1.0" } }, + "node_modules/@capacitor/device": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@capacitor/device/-/device-5.0.7.tgz", + "integrity": "sha512-sTYzGktRVK6giQCsoFtw+IGkEPGmFvIwi0pfFej5TRND1UHidkNZSpgMFBbjCYPbwsqXTcR3boYPcmxvl5iuJg==", + "peerDependencies": { + "@capacitor/core": "^5.0.0" + } + }, + "node_modules/@capacitor/filesystem": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-5.2.1.tgz", + "integrity": "sha512-mexkJHUbNhydzfJywEUTIGARlB/HRogrtbjCZdA+mQxOi07T2887a70CwFaYRu1nKLMoKoliTM5UsLSsdl0PlA==", + "peerDependencies": { + "@capacitor/core": "^5.1.1" + } + }, "node_modules/@capacitor/haptics": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-5.0.7.tgz", diff --git a/package.json b/package.json index 00c36157..a3e40878 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,13 @@ "sync:ios": "npx cap sync ios" }, "dependencies": { + "@capacitor-community/media": "^5.4.1", "@capacitor/android": "^5.6.0", "@capacitor/app": "5.0.7", "@capacitor/cli": "5.6.0", "@capacitor/core": "5.6.0", + "@capacitor/device": "^5.0.7", + "@capacitor/filesystem": "^5.2.1", "@capacitor/haptics": "5.0.7", "@capacitor/ios": "5.6.0", "@capacitor/keyboard": "5.0.8", diff --git a/src/components/Timetable/DownloadTimetableDialog.tsx b/src/components/Timetable/DownloadTimetableDialog.tsx index 3131cfcd..8e003208 100644 --- a/src/components/Timetable/DownloadTimetableDialog.tsx +++ b/src/components/Timetable/DownloadTimetableDialog.tsx @@ -8,6 +8,10 @@ import { useCallback, useRef, useState } from 'react'; import {createTimetableFromCourses, colorMapFromCourses} from '@/helpers/timetable'; import { useSettings } from '@/hooks/contexts/settings'; import { MinimalCourse } from '@/types/courses'; +import { Device } from '@capacitor/device'; +import { Media } from '@capacitor-community/media'; +import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'; +import { toast } from '../ui/use-toast'; const DownloadTimetableComponent = () => { const dict = useDictionary(); @@ -23,12 +27,25 @@ const DownloadTimetableComponent = () => { } setLoading(true); toPng(ref.current!, { cacheBust: true, pixelRatio: 3, filter: (node: HTMLElement) => node.id !== 'time_slot'}) - .then((dataUrl) => { - const link = document.createElement('a'); - link.download = 'timetable.png'; - link.href = dataUrl; - link.click(); - // navigator.clipboard.writeText(dataUrl); + .then(async (dataUrl) => { + const filename = new Date().toISOString() + '_timetable.png'; + const info = await Device.getInfo(); + if (info.platform === 'web') { + const link = document.createElement('a'); + link.download = filename; + link.href = dataUrl; + link.click(); + } else { + const albums = await Media.getAlbums(); + if (albums.albums.every(album => album.name !== 'NTHUMods')) { + await Media.createAlbum({ name: 'NTHUMods' }); + } + await Media.savePhoto({ + path: dataUrl, + albumIdentifier: 'NTHUMods', + fileName: filename, + }); + } }) .catch((err) => { console.error('oops, something went wrong!', err); @@ -59,11 +76,33 @@ const DownloadTimetableComponent = () => { const DownloadTimetableDialog = ({ onClose, icsfileLink }: { onClose: () => void, icsfileLink: string }) => { const dict = useDictionary(); - const handleDownloadCalendar = () => { - const link = document.createElement('a'); - link.download = 'calendar.ics'; - link.href = icsfileLink; - link.click(); + const handleDownloadCalendar = async () => { + const filename = `${new Date().toISOString()}_timetable.ics`; + if((await Device.getInfo()).platform === 'web') { + const link = document.createElement('a'); + link.download = filename + link.href = icsfileLink; + link.click(); + } else { + const res = await Filesystem.checkPermissions() + if (!res.publicStorage) { + const result = await Filesystem.requestPermissions(); + if (result.publicStorage != 'granted') { + toast({ + title: 'Permission Denied', + description: 'Please allow storage permission to download the file.', + }); + return; + } + } + Filesystem.downloadFile({ + path: `ics/${filename}`, + url: icsfileLink, + directory: Directory.Documents, + recursive: true, + }); + } + } return