mirror of
https://github.com/VueTubeApp/VueTube
synced 2024-11-24 04:05:16 +00:00
feat: implemented local playlist (#611)
This commit is contained in:
parent
f7ce9a62ea
commit
b1254b7376
14 changed files with 433 additions and 42 deletions
|
@ -18,6 +18,7 @@ module.exports = {
|
|||
"vue/multi-word-component-names": 0,
|
||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"prettier/prettier": ["error", {endOfLine: "auto"}]
|
||||
// 'prettier/prettier': ['error', { semi: false }],
|
||||
// semi: [2, 'never'],
|
||||
},
|
||||
|
|
|
@ -312,6 +312,7 @@
|
|||
:controls="controls"
|
||||
:sources="sources"
|
||||
:seeking="seeking"
|
||||
:disabled="disabled"
|
||||
@seeking="seeking = !seeking"
|
||||
@scrub="
|
||||
($refs.player.currentTime = $event), ($refs.audio.currentTime = $event)
|
||||
|
@ -384,6 +385,10 @@ export default {
|
|||
return [];
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
hide-details
|
||||
height="2"
|
||||
dense
|
||||
:disabled="disabled"
|
||||
color="transparent"
|
||||
thumb-color="primary"
|
||||
track-color="transparent"
|
||||
|
@ -85,6 +86,10 @@ export default {
|
|||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ["scrub", "seeking"],
|
||||
data: () => ({
|
||||
|
|
41
NUXT/components/Playlist/playlistAlert.vue
Normal file
41
NUXT/components/Playlist/playlistAlert.vue
Normal file
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<v-dialog v-if="dialog" width="500">
|
||||
<v-card
|
||||
class="rounded-lg"
|
||||
:class="
|
||||
$vuetify.theme.dark ? 'background lighten-1' : 'background darken-1'
|
||||
"
|
||||
>
|
||||
<v-card-title class="text-h5">Save To Playlist</v-card-title>
|
||||
<v-checkbox
|
||||
v-for="(playlist, index) in playlist"
|
||||
:key="index"
|
||||
:v-model="
|
||||
!(
|
||||
playlist.videos.findIndex(
|
||||
(playlistVideo) => playlistVideo.id !== currentVideo.id
|
||||
) === -1
|
||||
)
|
||||
"
|
||||
:label="playlist.name"
|
||||
/>
|
||||
<v-divider />
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" text @click="$emit('close')"> Done </v-btn>
|
||||
</v-card-actions>
|
||||
</v-card></v-dialog
|
||||
>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: { dialog: Boolean, currentVideo: { type: Object, required: true } },
|
||||
computed: {
|
||||
playlists() {
|
||||
return this.$store.state.playlist.playlists;
|
||||
},
|
||||
},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<v-card
|
||||
<v-btn
|
||||
v-ripple
|
||||
class="background d-flex flex-row overflow-hidden mb-4 mx-4"
|
||||
text
|
||||
class="background d-flex flex-row overflow-hidden mb-4 mx-7 mainCard px-0"
|
||||
to="/playlist"
|
||||
style="height: 6rem !important"
|
||||
:class="
|
||||
$store.state.tweaks.roundThumb && $store.state.tweaks.roundTweak > 0
|
||||
|
@ -15,11 +17,11 @@
|
|||
? `${$store.state.tweaks.roundTweak / 3}rem`
|
||||
: '0',
|
||||
}"
|
||||
flat
|
||||
@click.native="clickHandler"
|
||||
>
|
||||
<v-img
|
||||
contain
|
||||
src="/dev.svg"
|
||||
:src="thumbnail"
|
||||
class="background"
|
||||
style="position: relative; max-width: 8rem !important"
|
||||
:class="$vuetify.theme.dark ? 'lighten-3' : 'darken-3'"
|
||||
|
@ -33,24 +35,24 @@
|
|||
class="d-flex flex-column justify-center align-center background-opaque"
|
||||
style="position: absolute; top: 0; right: 0; width: 50%; height: 100%"
|
||||
>
|
||||
<div>420</div>
|
||||
<div>{{ playlist.videos.length }}</div>
|
||||
<v-icon>mdi-playlist-play</v-icon>
|
||||
</div>
|
||||
</v-img>
|
||||
<div class="pa-4" v-emoji style="font-size: 0.75rem !important">
|
||||
<b>Work in Progress</b>
|
||||
<div v-emoji class="pa-4 text-left" style="font-size: 0.75rem !important">
|
||||
<b>{{ playlist.name }}</b>
|
||||
|
||||
<div
|
||||
class="background--text caption mt-2"
|
||||
:class="$vuetify.theme.dark ? 'text--lighten-4' : 'text--darken-4'"
|
||||
>
|
||||
Bottom Text <br />
|
||||
420 videos
|
||||
{{ playlist.videos.length }} videos
|
||||
</div>
|
||||
</div>
|
||||
<v-spacer></v-spacer>
|
||||
<div class="d-flex flex-column">
|
||||
<v-btn
|
||||
<!-- <v-btn
|
||||
text
|
||||
tile
|
||||
elevation="0"
|
||||
|
@ -67,7 +69,39 @@
|
|||
style="width: 2rem !important"
|
||||
>
|
||||
<v-icon>mdi-playlist-plus</v-icon>
|
||||
</v-btn>
|
||||
</v-btn> -->
|
||||
</div>
|
||||
</v-card>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
playlist: { type: Object, required: true },
|
||||
},
|
||||
computed: {
|
||||
thumbnail() {
|
||||
try {
|
||||
const videoId =
|
||||
this.playlist.videos.length === 0 ? "" : this.playlist.videos[0].id;
|
||||
return `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`;
|
||||
} catch (e) {
|
||||
alert(e.message);
|
||||
return `https://img.youtube.com/vi//maxresdefault.jpg`;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clickHandler() {
|
||||
this.$emit("click");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mainCard {
|
||||
text-transform: none !important;
|
||||
letter-spacing: normal !important;
|
||||
}
|
||||
</style>
|
101
NUXT/components/Playlist/playlistVideoCard.vue
Normal file
101
NUXT/components/Playlist/playlistVideoCard.vue
Normal file
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<v-card
|
||||
v-ripple
|
||||
class="background d-flex flex-row overflow-hidden mb-4 mx-4"
|
||||
style="height: 4.5rem !important"
|
||||
:class="
|
||||
$store.state.tweaks.roundThumb && $store.state.tweaks.roundTweak > 0
|
||||
? $vuetify.theme.dark
|
||||
? 'lighten-1'
|
||||
: 'darken-1'
|
||||
: ''
|
||||
"
|
||||
:style="{
|
||||
borderRadius: $store.state.tweaks.roundThumb
|
||||
? `${$store.state.tweaks.roundTweak / 3}rem`
|
||||
: '0',
|
||||
}"
|
||||
flat
|
||||
>
|
||||
<v-card
|
||||
class="d-flex flex-row w-50 elevation-0"
|
||||
:to="`/watch?v=${video.id}`"
|
||||
>
|
||||
<v-img
|
||||
:src="thumbnail"
|
||||
aspect-ratio="1.7778"
|
||||
style="position: relative; width: 8rem"
|
||||
:class="$vuetify.theme.dark ? 'lighten-3' : 'darken-3'"
|
||||
:style="{
|
||||
borderRadius: $store.state.tweaks.roundThumb
|
||||
? `${$store.state.tweaks.roundTweak / 3}rem`
|
||||
: '0',
|
||||
}"
|
||||
>
|
||||
</v-img>
|
||||
<div
|
||||
v-emoji
|
||||
style="font-size: 0.75rem !important"
|
||||
class="d-flex flex-column ml-2"
|
||||
>
|
||||
<b
|
||||
class="text-left"
|
||||
style="
|
||||
{
|
||||
height: 1.5rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
"
|
||||
>{{ video.title }}
|
||||
</b>
|
||||
<div
|
||||
class="background--text caption mt-2 text-left d-inline-block text-truncate"
|
||||
:class="$vuetify.theme.dark ? 'text--lighten-4' : 'text--darken-4'"
|
||||
style="
|
||||
{
|
||||
height: 0.75rem;
|
||||
}
|
||||
"
|
||||
>
|
||||
{{ video.channel }}
|
||||
</div>
|
||||
</div>
|
||||
</v-card>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<div class="d-flex w-50 flex-column">
|
||||
<v-btn
|
||||
text
|
||||
tile
|
||||
elevation="0"
|
||||
class="flex-grow-1"
|
||||
style="width: 2rem !important"
|
||||
@click="deleted"
|
||||
>
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: { video: { type: Object, required: true } },
|
||||
computed: {
|
||||
thumbnail() {
|
||||
return `https://img.youtube.com/vi/${this.video.id}/maxresdefault.jpg`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
deleted() {
|
||||
this.$emit("deleted");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -6,7 +6,11 @@
|
|||
v-show="!search"
|
||||
class="my-auto ml-4"
|
||||
v-text="
|
||||
$route.path.includes('channel') ? $store.state.channel.title : page
|
||||
$route.path.includes('channel')
|
||||
? $store.state.channel.title
|
||||
: $route.path.includes('playlist')
|
||||
? $store.state.playlist.currentPlaylist.name
|
||||
: page
|
||||
"
|
||||
/>
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"@capacitor/status-bar": "^1.0.8",
|
||||
"core-js": "^3.25.0",
|
||||
"nuxt": "^2.15.8",
|
||||
"uuid": "^9.0.0",
|
||||
"vue": "^2.7.10",
|
||||
"vue-server-renderer": "^2.7.10",
|
||||
"vue-template-compiler": "^2.7.10",
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<playlist-card />
|
||||
</div>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import playlistCard from "../../components/playlistCard.vue";
|
||||
export default {
|
||||
components: {
|
||||
playlistCard,
|
||||
},
|
||||
};
|
||||
export default {};
|
||||
</script>
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="d-flex justify-space-between mb-2 mx-7">
|
||||
<h4
|
||||
class="ml-7 mb-2 background--text"
|
||||
class="background--text w-50"
|
||||
:class="$vuetify.theme.dark ? 'text--lighten-3' : 'text--darken-3'"
|
||||
>
|
||||
Local Playlists
|
||||
</h4>
|
||||
<playlist-card />
|
||||
<v-btn text tile elevation="0" class="w-5-0" @click="dialog = true">
|
||||
<v-icon>mdi-plus</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div class="d-flex flex-column-reverse">
|
||||
<playlist-card
|
||||
v-for="(playlist, index) in playlists"
|
||||
:key="index"
|
||||
:playlist="playlist"
|
||||
@click="changeToPlaylist(index)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<v-btn
|
||||
text
|
||||
class="entry text-left setting-btn no-spacing"
|
||||
|
@ -27,13 +40,62 @@
|
|||
>
|
||||
History
|
||||
</v-btn>
|
||||
<!-- Create Playlist Dialog -->
|
||||
<v-dialog v-model="dialog" width="500">
|
||||
<v-card
|
||||
class="rounded-lg"
|
||||
:class="
|
||||
$vuetify.theme.dark ? 'background lighten-1' : 'background darken-1'
|
||||
"
|
||||
>
|
||||
<v-card-title class="text-h5">Create Playlist</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field v-model="playlistName" label="Playlist Name" solo />
|
||||
</v-card-text>
|
||||
<v-divider />
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" text @click="dialog = false">
|
||||
{{ lang.cancel }}
|
||||
</v-btn>
|
||||
<v-btn color="primary" text @click="createPlaylist()">
|
||||
{{ lang.create }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card></v-dialog
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import playlistCard from "../components/playlistCard.vue";
|
||||
import playlistCard from "~/components/Playlist/playlistCard.vue";
|
||||
export default {
|
||||
components: { playlistCard },
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
lang: {},
|
||||
playlistName: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
playlists() {
|
||||
return this.$store.state.playlist.playlists;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const lang = this.$lang();
|
||||
this.lang = lang.mods.developer;
|
||||
},
|
||||
methods: {
|
||||
createPlaylist: function () {
|
||||
this.$store.commit("playlist/createPlaylist", this.playlistName);
|
||||
this.dialog = false;
|
||||
},
|
||||
changeToPlaylist: function (videoIndex) {
|
||||
this.$store.commit("playlist/changeToPlaylist", videoIndex);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
30
NUXT/pages/playlist.vue
Normal file
30
NUXT/pages/playlist.vue
Normal file
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<div>
|
||||
<playlist-video-card
|
||||
v-for="(video, index) in playlist.videos"
|
||||
:key="index"
|
||||
:video="video"
|
||||
@deleted="deletePlaylistVideo(video)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import playlistVideoCard from "~/components/playlist/playlistVideoCard.vue";
|
||||
export default {
|
||||
components: { playlistVideoCard },
|
||||
computed: {
|
||||
playlist() {
|
||||
return this.$store.state.playlist.currentPlaylist;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
deletePlaylistVideo(target) {
|
||||
this.$store.commit("playlist/removeFromPlaylist", {
|
||||
playlistIndex: this.playlist.index,
|
||||
video: target,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -9,6 +9,7 @@
|
|||
:video="video"
|
||||
:sources="sources"
|
||||
:recommends="recommends"
|
||||
:disabled="saveDialog"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -273,6 +274,30 @@
|
|||
}"
|
||||
/>
|
||||
</div>
|
||||
<v-dialog v-model="saveDialog" width="500">
|
||||
<v-card
|
||||
class="rounded-lg"
|
||||
:class="
|
||||
$vuetify.theme.dark ? 'background lighten-1' : 'background darken-1'
|
||||
"
|
||||
>
|
||||
<v-card-title class="text-h5">Save To Playlist</v-card-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-checkbox
|
||||
v-for="(playlist, index) in playlists"
|
||||
:key="index"
|
||||
v-model="playlistsCheckbox[index]"
|
||||
class="mx-5"
|
||||
:label="playlist.name"
|
||||
@change="updatePlaylist($event, index)"
|
||||
/>
|
||||
<v-divider />
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" text @click="saveDialog = false"> Done </v-btn>
|
||||
</v-card-actions>
|
||||
</v-card></v-dialog
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -304,6 +329,12 @@ export default {
|
|||
data: function () {
|
||||
return this.initializeState();
|
||||
},
|
||||
|
||||
computed: {
|
||||
playlists() {
|
||||
return this.$store.state.playlist.playlists;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// Watch for change in the route query string (in this case, ?v=xxxxxxxx to ?v=yyyyyyyy)
|
||||
$route: {
|
||||
|
@ -356,6 +387,14 @@ export default {
|
|||
title: this.video.title,
|
||||
channel: this.video.channelName,
|
||||
});
|
||||
|
||||
this.playlistsCheckbox = this.playlists.map(
|
||||
(playlist) =>
|
||||
playlist.videos.findIndex(
|
||||
(playlistVideo) => playlistVideo.id === this.video.id
|
||||
) !== -1
|
||||
);
|
||||
|
||||
//--- API WatchTime call ---//
|
||||
if (this.$store.state.watchTelemetry) {
|
||||
this.playbackTracking = result.playbackTracking;
|
||||
|
@ -459,8 +498,9 @@ export default {
|
|||
{
|
||||
name: "Save",
|
||||
icon: "mdi-plus-box-multiple-outline",
|
||||
actionName: "enqueue",
|
||||
disabled: true,
|
||||
// action: this.save()
|
||||
actionName: "save",
|
||||
disabled: false,
|
||||
},
|
||||
// {
|
||||
// name: "Quality",
|
||||
|
@ -484,13 +524,14 @@ export default {
|
|||
interval: null,
|
||||
video: null,
|
||||
backHierarchy: [],
|
||||
saveDialog: false,
|
||||
playlistsCheckbox: [],
|
||||
};
|
||||
},
|
||||
|
||||
mountedInit() {
|
||||
this.startTime = Math.floor(Date.now() / 1000);
|
||||
this.getVideo();
|
||||
|
||||
// Reset vertical scrolling
|
||||
const scrollableList = document.querySelectorAll(".overflow-y-auto");
|
||||
scrollableList.forEach((scrollable) => {
|
||||
|
@ -514,6 +555,28 @@ export default {
|
|||
this.$vuetube.addBackAction(dismissComment);
|
||||
}
|
||||
},
|
||||
|
||||
save() {
|
||||
this.saveDialog = true;
|
||||
},
|
||||
|
||||
updatePlaylist(event, index) {
|
||||
if (event) {
|
||||
this.$store.commit("playlist/addToPlaylist", {
|
||||
video: {
|
||||
id: this.video.id,
|
||||
title: this.video.title,
|
||||
channel: this.video.channelName,
|
||||
},
|
||||
index,
|
||||
});
|
||||
} else {
|
||||
this.$store.commit("playlist/removeFromPlaylist", {
|
||||
video: this.video,
|
||||
playlistIndex: index,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
51
NUXT/store/playlist/index.js
Normal file
51
NUXT/store/playlist/index.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
export const state = () => ({
|
||||
playlists: [],
|
||||
currentPlaylist: null,
|
||||
});
|
||||
|
||||
// Shape of playlists
|
||||
// [playlist, playlist]
|
||||
|
||||
// Shape of playlist
|
||||
// {name: string, videos: []}
|
||||
|
||||
// Shape of currentPlaylist
|
||||
// {index: number, name: string, videos: []}
|
||||
|
||||
export const mutations = {
|
||||
initPlaylists(state) {
|
||||
if (process.client) {
|
||||
// read local storage and parse the list of objects
|
||||
state.playlists = JSON.parse(localStorage.getItem("playlists"));
|
||||
}
|
||||
},
|
||||
createPlaylist(state, name) {
|
||||
state.playlists.push({ name, videos: [] });
|
||||
localStorage.setItem("playlists", JSON.stringify(state.playlists));
|
||||
},
|
||||
removePlaylist(state, index) {
|
||||
state.playlists.splice(index, 1);
|
||||
localStorage.setItem("playlists", JSON.stringify(state.playlists));
|
||||
},
|
||||
addToPlaylist(state, { index, video }) {
|
||||
state.playlists[index].videos.unshift(video);
|
||||
localStorage.setItem("playlists", JSON.stringify(state.playlists));
|
||||
},
|
||||
removeFromPlaylist(state, { playlistIndex, video }) {
|
||||
const videoIndex = state.playlists[playlistIndex].videos.findIndex(
|
||||
(playlistVideo) => playlistVideo.id === video.id
|
||||
);
|
||||
if (videoIndex === -1) throw new Error("Unable To Find Video");
|
||||
state.playlists[playlistIndex].videos.splice(videoIndex, 1);
|
||||
localStorage.setItem("playlists", JSON.stringify(state.playlists));
|
||||
},
|
||||
changeToPlaylist(state, videoIndex) {
|
||||
state.currentPlaylist = {
|
||||
index: videoIndex,
|
||||
...state.playlists[videoIndex],
|
||||
};
|
||||
},
|
||||
exitPlaylist(state) {
|
||||
state.currentPlaylist = null;
|
||||
},
|
||||
};
|
|
@ -9,16 +9,16 @@ 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 'CapacitorCommunityHttp', :path => '../../node_modules/@capacitor-community/http'
|
||||
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 'CapacitorShare', :path => '../../node_modules/@capacitor/share'
|
||||
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
|
||||
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
|
||||
pod 'CapacitorToast', :path => '../../node_modules/@capacitor/toast'
|
||||
pod 'HugotomaziCapacitorNavigationBar', :path => '../../node_modules/@hugotomazi/capacitor-navigation-bar'
|
||||
pod 'CapacitorCommunityHttp', :path => '..\..\node_modules\@capacitor-community\http'
|
||||
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 'CapacitorShare', :path => '..\..\node_modules\@capacitor\share'
|
||||
pod 'CapacitorSplashScreen', :path => '..\..\node_modules\@capacitor\splash-screen'
|
||||
pod 'CapacitorStatusBar', :path => '..\..\node_modules\@capacitor\status-bar'
|
||||
pod 'CapacitorToast', :path => '..\..\node_modules\@capacitor\toast'
|
||||
pod 'HugotomaziCapacitorNavigationBar', :path => '..\..\node_modules\@hugotomazi\capacitor-navigation-bar'
|
||||
pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue