Skip to content

Commit

Permalink
Feat: add/remove samples (#31)
Browse files Browse the repository at this point in the history
Fixes #1
Fixes #2
Fixes #4
Fixes #9
Fixes #10
Fixes #14
Fixes #16
Fixes #23
  • Loading branch information
Uninen authored Feb 15, 2022
1 parent d0a814c commit d51369b
Show file tree
Hide file tree
Showing 16 changed files with 373 additions and 151 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"dependencies": {
"@nuxt/devalue": "^2.0.0",
"add": "^2.0.6",
"add-filename-increment": "^1.0.0",
"autoprefixer": "^10.4",
"electron-settings": "^4.0",
Expand All @@ -55,10 +56,13 @@
"unused-filename": "^4.0.0",
"v8-compile-cache": "^2.3.0",
"vue": "^3.2",
"vue-router": "^4.0"
"vue-router": "^4.0",
"wavesurfer.js": "^6.0.1",
"yarn": "^1.22.17"
},
"devDependencies": {
"@types/electron-devtools-installer": "^2.2",
"@types/wavesurfer.js": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^5.11",
"@typescript-eslint/parser": "^5.11",
"@vitejs/plugin-vue": "^2.2",
Expand Down
49 changes: 47 additions & 2 deletions packages/main/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { app, BrowserWindow, ipcMain, dialog } from 'electron'
import { app, BrowserWindow, ipcMain, dialog, protocol } from 'electron'
import { join } from 'path'
import { mkdir } from 'fs/promises'
import { mkdir, unlink } from 'fs/promises'
import { URL } from 'url'
// import devalue from '@nuxt/devalue'
import Store from 'electron-store'
import 'v8-compile-cache'
import type { Sample } from 'root/types'

import {
enforceApplicationFolder,
Expand All @@ -25,6 +26,7 @@ const store = new Store({
const isSingleInstance = app.requestSingleInstanceLock()
const userDataPath = app.getPath('userData')
const samplePath = join(userDataPath, 'samples')
const protocolName = 'slip-board'
console.log('userDataPath', userDataPath)
pathAvailable(samplePath).then((available) => {
if (available) {
Expand All @@ -46,6 +48,13 @@ const mainPageUrl =
? import.meta.env.VITE_DEV_SERVER_URL
: new URL('../renderer/dist/index.html', 'file://' + __dirname).toString()

protocol.registerSchemesAsPrivileged([
{
scheme: 'slip-board',
privileges: { secure: true, standard: true, supportFetchAPI: true },
},
])

if (!isSingleInstance) {
app.quit()
process.exit(0)
Expand Down Expand Up @@ -105,8 +114,44 @@ ipcMain.on('openSamplesFilepicker', () => {
})
})

ipcMain.on('processDroppedSamples', (event, fileList: string[]) => {
console.log('processing dropped samples')

filepathsToSamples(samplePath, fileList).then((samples) => {
console.log('got samples: ', samples)
mainWindow.webContents.send('addedSamples', samples)
})
})

ipcMain.on('confirmSampleDelete', (event, sample: Sample) => {
console.log('confirmSampleDelete payload: ', sample)

const answer = dialog.showMessageBoxSync({
message: 'Are you sure?',
type: 'warning',
detail: 'This action cannot be undone.',
buttons: ['Yes', 'No'],
})

if (answer === 0) {
console.log('deleting sample: ', sample)
mainWindow.webContents.send('deletedSample', sample.id)
unlink(sample.path).then(() => {
console.log('succesfully deleted sample')
})
}
})

function initMain() {
return new Promise<void>((resolve) => {
protocol.registerFileProtocol(protocolName, (request, callback) => {
const url = request.url.replace(`${protocolName}://`, '')
try {
return callback(decodeURIComponent(url))
} catch (error) {
console.error(error)
}
})
resolve()
})
}
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer/assets/main.postcss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@tailwind utilities;

html {
@apply bg-black text-gray-200;
@apply bg-[#1C1E20] text-gray-200;
font-size: 14px;
}

Expand Down
54 changes: 49 additions & 5 deletions packages/renderer/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,48 @@ store.initApp()
const uiMode = computed(() => store.ui.mode)
const headerTextColor = computed(() => store.headerTextColor)
const headerBgColor = computed(() => store.headerBgColor)
const dragMode = computed(() => store.ui.dragMode)
function toggleUiMode() {
if (uiMode.value === 'play') {
store.ui.mode = 'edit'
console.log('changed uiMode to edit')
} else {
store.ui.mode = 'play'
console.log('changed uiMode to play')
store.setActiveSample('')
}
}
document.addEventListener('drop', (event) => {
event.preventDefault()
event.stopPropagation()
store.ui.dragMode = false
const filePaths: string[] = []
// @ts-expect-error
for (const f of event.dataTransfer.files) {
// Using the path attribute to get absolute file path
// @ts-expect-error
filePaths.push(f.path)
// @ts-expect-error
console.log('File Path of dragged files: ', f.path)
}
window.api.send('processDroppedSamples', filePaths)
})
document.addEventListener('dragover', (e) => {
e.preventDefault()
e.stopPropagation()
})
document.addEventListener('dragenter', () => {
store.ui.dragMode = true
console.log('File is in the Drop Space')
})
document.addEventListener('dragleave', () => {
store.ui.dragMode = false
console.log('File has left the Drop Space')
})
window.api.receive('blur', () => {
store.changeFocus(false)
})
Expand All @@ -32,7 +63,9 @@ window.api.receive('addedSamples', (samples: Sample[]) => {
store.addSamples(samples)
})
console.log('Renderer setup DONE')
window.api.receive('deletedSample', (id: string) => {
store.deleteSample(id)
})
</script>

<style>
Expand All @@ -45,12 +78,23 @@ console.log('Renderer setup DONE')
<template>
<div
id="header"
class="h-[52px] w-full flex justify-end items-center os-draggable pr-[18px] flex-none fixed"
class="h-[52px] w-full flex items-center os-draggable pr-[18px] flex-none fixed"
:class="{
'justify-end': !dragMode,
'!bg-green-600 justify-center': dragMode,
}"
>
<div @click="toggleUiMode" class="px-3 py-1 rounded hover:bg-white/10">
<div
v-if="!dragMode"
@click="toggleUiMode"
class="flex justify-end px-3 py-1 rounded hover:bg-white/10"
>
<div v-if="uiMode === 'play'">Play Mode</div>
<div v-else>Edit Mode</div>
</div>
<div v-else class="w-full text-xl text-center text-white">
Drop samples to import
</div>
</div>
<router-view />
</template>
15 changes: 0 additions & 15 deletions packages/renderer/src/components/AppNavigation.vue

This file was deleted.

82 changes: 82 additions & 0 deletions packages/renderer/src/components/SampleCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useStore } from '@/store'
import WaveSurfer from 'wavesurfer.js'
import type { Sample } from 'root/types'
const store = useStore()
const mode = computed(() => store.ui.mode)
const activeSample = computed(() => store.ui.activeSample)
const wavecontainer = ref(null)
const player = ref<WaveSurfer>()
const isPlaying = ref(false)
const props = defineProps<{
sample: Sample
}>()
function selectSample() {
console.log('SAMPLE CLICKED')
if (mode.value === 'play') {
if (isPlaying.value) {
player.value?.stop()
isPlaying.value = false
} else {
player.value?.play()
isPlaying.value = true
}
}
if (activeSample.value === props.sample.id) {
store.setActiveSample('')
} else {
store.setActiveSample(props.sample.id)
}
}
watch(wavecontainer, (newContainer) => {
if (newContainer) {
player.value = WaveSurfer.create({
container: newContainer,
waveColor: 'violet',
progressColor: 'purple',
// cursorColor: '#fff',
// barWidth: 2,
// barHeight: 1,
// barGap: 1,
interact: false,
height: 100,
hideScrollbar: true,
// responsive: true,
})
player.value.on('finish', () => {
store.setActiveSample('')
player.value?.stop()
})
player.value.load('slip-board://' + props.sample.path)
// player.value.load('file://' + props.sample.path)
}
})
</script>
<template>
<div
class="h-[100px] w-[200px] border-2 rounded flex flex-col overflow-hidden mx-1 my-1 bg-white/5"
:class="{
'border-indigo-500/60': activeSample === sample.id,
'border-[#1C1E20]': activeSample !== sample.id,
}"
@click="selectSample"
>
<div class="flex-1 px-3 pt-2">
<h4>{{ sample.name }}</h4>

<div ref="wavecontainer"></div>
</div>
<div v-if="mode === 'edit'" class="flex justify-end w-full px-2 py-1">
<button class="btn">Edit</button>
</div>
</div>
</template>
29 changes: 29 additions & 0 deletions packages/renderer/src/components/SampleEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
import { computed, ref, watch, toRaw } from 'vue'
import { useStore } from '@/store'
import type { Sample } from 'root/types'
const store = useStore()
const mode = computed(() => store.ui.mode)
const sample = computed(() => store.getSelectedSample)
function confirmDelete() {
const obj = toRaw(sample.value)
console.log('confirmSampleDelete', obj)
window.api.send('confirmSampleDelete', obj)
}
</script>
<template>
<div
v-if="sample && mode === 'edit'"
class="bg-black absolute top-[52px] bottom-0 right-0 w-[280px] px-3 py-3"
>
<h4>{{ sample.name }}</h4>

<p class="my-4 text-xs">{{ sample.path }}</p>

<hr />

<button class="btn" @click="confirmDelete">Delete sample</button>
</div>
</template>
17 changes: 0 additions & 17 deletions packages/renderer/src/pages/About.vue

This file was deleted.

Loading

0 comments on commit d51369b

Please sign in to comment.