Yann commited on
Commit
5b508b2
Β·
1 Parent(s): c529a9f

removed all firebase features

Browse files
.firebaserc DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "projects": {
3
- "default": "signal-9546d"
4
- }
5
- }
 
 
 
 
 
 
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: Midi-Demo
3
- emoji: 🎷
4
- colorFrom: white
5
- colorTo: pink
6
  sdk: docker
7
  pinned: false
8
  ---
 
1
  ---
2
+ title: Signal Midi Frontend Demo
3
+ emoji: πŸ§‘β€πŸ³
4
+ colorFrom: yellow
5
+ colorTo: green
6
  sdk: docker
7
  pinned: false
8
  ---
firebase.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "firestore": {
3
- "rules": "firestore.rules",
4
- "indexes": "firestore.indexes.json"
5
- },
6
- "emulators": {
7
- "auth": {
8
- "port": 9099
9
- },
10
- "firestore": {
11
- "port": 8080
12
- },
13
- "ui": {
14
- "enabled": true
15
- }
16
- }
17
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
firestore.indexes.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "indexes": [],
3
- "fieldOverrides": []
4
- }
 
 
 
 
 
firestore.rules DELETED
@@ -1,15 +0,0 @@
1
- rules_version = '2';
2
- service cloud.firestore {
3
- match /databases/{database}/documents {
4
- match /songs/{songId} {
5
- allow read, delete: if request.auth != null && request.auth.uid == resource.data.userId;
6
- allow update: if request.auth != null && request.auth.uid == resource.data.userId && !('uid' in request.writeFields);
7
- allow create: if request.auth != null && request.auth.uid == request.resource.data.userId;
8
- }
9
- match /songData/{songDataId} {
10
- allow read, delete: if request.auth != null && request.auth.uid == resource.data.userId;
11
- allow update: if request.auth != null && request.auth.uid == resource.data.userId && !('uid' in request.writeFields);
12
- allow create: if request.auth != null && request.auth.uid == request.resource.data.userId;
13
- }
14
- }
15
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
package.json CHANGED
@@ -8,9 +8,7 @@
8
  "serve": "npx http-server dist",
9
  "test": "jest",
10
  "format": "prettier --write src",
11
- "lint": "prettier --check src",
12
- "firebase": "firebase emulators:start",
13
- "firebase:deploy": "firebase deploy"
14
  },
15
  "repository": {
16
  "type": "git",
@@ -41,8 +39,6 @@
41
  "@sentry/react": "^7.69.0",
42
  "@sentry/tracing": "^7.69.0",
43
  "color": "^4.2.3",
44
- "firebase": "^10.4.0",
45
- "firebaseui": "^6.1.0",
46
  "gl-matrix": "^3.4.3",
47
  "lodash": "^4.17.21",
48
  "mdi-react": "^9.2.0",
 
8
  "serve": "npx http-server dist",
9
  "test": "jest",
10
  "format": "prettier --write src",
11
+ "lint": "prettier --check src"
 
 
12
  },
13
  "repository": {
14
  "type": "git",
 
39
  "@sentry/react": "^7.69.0",
40
  "@sentry/tracing": "^7.69.0",
41
  "color": "^4.2.3",
 
 
42
  "gl-matrix": "^3.4.3",
43
  "lodash": "^4.17.21",
44
  "mdi-react": "^9.2.0",
src/common/song/Song.ts CHANGED
@@ -9,7 +9,6 @@ import {
9
  transaction,
10
  } from "mobx"
11
  import { createModelSchema, list, object, primitive } from "serializr"
12
- import { FirestoreSong, FirestoreSongData } from "../../firebase/song"
13
  import { TIME_BASE } from "../../main/Constants"
14
  import { isNotUndefined } from "../helpers/array"
15
  import { Measure } from "../measure/Measure"
@@ -25,8 +24,6 @@ export default class Song {
25
  timebase: number = TIME_BASE
26
  name: string = ""
27
  fileHandle: FileSystemFileHandle | null = null
28
- firestoreReference: DocumentReference<FirestoreSong> | null = null
29
- firestoreDataReference: DocumentReference<FirestoreSongData> | null = null
30
  isSaved = true
31
 
32
  constructor() {
 
9
  transaction,
10
  } from "mobx"
11
  import { createModelSchema, list, object, primitive } from "serializr"
 
12
  import { TIME_BASE } from "../../main/Constants"
13
  import { isNotUndefined } from "../helpers/array"
14
  import { Measure } from "../measure/Measure"
 
24
  timebase: number = TIME_BASE
25
  name: string = ""
26
  fileHandle: FileSystemFileHandle | null = null
 
 
27
  isSaved = true
28
 
29
  constructor() {
src/community/components/Navigation.tsx CHANGED
@@ -1,6 +1,5 @@
1
  import styled from "@emotion/styled"
2
  import { FC } from "react"
3
- import { auth } from "../../firebase/firebase"
4
  import { UserButtonContent } from "../../main/components/Navigation/UserButtonContent"
5
  import { useStores } from "../hooks/useStores"
6
 
@@ -26,9 +25,6 @@ const NavigationWrapper = styled.div`
26
  `
27
 
28
  export const Navigation: FC = () => {
29
- const {
30
- authStore: { user },
31
- } = useStores()
32
 
33
  return (
34
  <NavigationWrapper>
@@ -36,13 +32,6 @@ export const Navigation: FC = () => {
36
  <LogoWrapper href="/">
37
  <img src="logo-white.svg" style={{ height: "1.7rem" }} />
38
  </LogoWrapper>
39
- <UserButtonContent
40
- user={user}
41
- onClickSignIn={() => {}}
42
- onClickSignOut={async () => {
43
- await auth.signOut()
44
- }}
45
- />
46
  </Container>
47
  </NavigationWrapper>
48
  )
 
1
  import styled from "@emotion/styled"
2
  import { FC } from "react"
 
3
  import { UserButtonContent } from "../../main/components/Navigation/UserButtonContent"
4
  import { useStores } from "../hooks/useStores"
5
 
 
25
  `
26
 
27
  export const Navigation: FC = () => {
 
 
 
28
 
29
  return (
30
  <NavigationWrapper>
 
32
  <LogoWrapper href="/">
33
  <img src="logo-white.svg" style={{ height: "1.7rem" }} />
34
  </LogoWrapper>
 
 
 
 
 
 
 
35
  </Container>
36
  </NavigationWrapper>
37
  )
src/community/components/RootView.tsx CHANGED
@@ -2,7 +2,6 @@ import styled from "@emotion/styled"
2
  import { FC } from "react"
3
  import { BottomPlayer } from "./BottomPlayer"
4
  import { Navigation } from "./Navigation"
5
- import { SongList } from "./SongList"
6
 
7
  const Container = styled.div`
8
  display: flex;
@@ -35,8 +34,6 @@ export const RootView: FC = () => {
35
  <Navigation />
36
  <Content>
37
  <Inner>
38
- <Title>Community Tracks</Title>
39
- <SongList />
40
  </Inner>
41
  </Content>
42
  <BottomPlayer />
 
2
  import { FC } from "react"
3
  import { BottomPlayer } from "./BottomPlayer"
4
  import { Navigation } from "./Navigation"
 
5
 
6
  const Container = styled.div`
7
  display: flex;
 
34
  <Navigation />
35
  <Content>
36
  <Inner>
 
 
37
  </Inner>
38
  </Content>
39
  <BottomPlayer />
src/community/components/SongList.tsx DELETED
@@ -1,39 +0,0 @@
1
- import { observer } from "mobx-react-lite"
2
- import { FC, useEffect } from "react"
3
- import { useStores } from "../hooks/useStores"
4
- import { SongListItem } from "./SongListItem"
5
-
6
- export const SongList: FC = observer(() => {
7
- const { authStore, communitySongStore } = useStores()
8
-
9
- useEffect(() => {
10
- ;(async () => {
11
- if (authStore.user) {
12
- // TODO: Remove checking user is logged-in
13
- await communitySongStore.load()
14
- }
15
- })()
16
- }, [])
17
-
18
- const { songs } = communitySongStore
19
-
20
- const items = songs.map((d) => ({
21
- song: {
22
- id: d.id,
23
- name: d.data().name,
24
- updatedAt: new Date(d.data().updatedAt.toDate()),
25
- },
26
- user: {
27
- name: d.data().userId,
28
- photoURL: "",
29
- },
30
- }))
31
-
32
- return (
33
- <>
34
- {items.map((s) => (
35
- <SongListItem song={s.song} user={s.user} />
36
- ))}
37
- </>
38
- )
39
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/community/stores/CommunitySongStore.ts DELETED
@@ -1,22 +0,0 @@
1
- import { QueryDocumentSnapshot } from "@firebase/firestore"
2
- import { makeObservable, observable } from "mobx"
3
- import { FirestoreSong, getCurrentUserSongs } from "../../firebase/song"
4
-
5
- export class CommunitySongStore {
6
- isLoading = false
7
- songs: QueryDocumentSnapshot<FirestoreSong>[] = []
8
-
9
- constructor() {
10
- makeObservable(this, {
11
- isLoading: observable,
12
- songs: observable,
13
- })
14
- }
15
-
16
- async load() {
17
- this.isLoading = true
18
- const snapshot = await getCurrentUserSongs()
19
- this.songs = snapshot.docs
20
- this.isLoading = false
21
- }
22
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/community/stores/RootStore.ts CHANGED
@@ -1,13 +1,9 @@
1
  import Player from "../../common/player"
2
  import { SoundFontSynth } from "../../main/services/SoundFontSynth"
3
- import { AuthStore } from "../../main/stores/AuthStore"
4
- import { CommunitySongStore } from "./CommunitySongStore"
5
  import { SongStore } from "./SongStore"
6
 
7
  export default class RootStore {
8
  readonly songStore = new SongStore()
9
- readonly authStore = new AuthStore()
10
- readonly communitySongStore = new CommunitySongStore()
11
  readonly player: Player
12
  readonly synth: SoundFontSynth
13
 
 
1
  import Player from "../../common/player"
2
  import { SoundFontSynth } from "../../main/services/SoundFontSynth"
 
 
3
  import { SongStore } from "./SongStore"
4
 
5
  export default class RootStore {
6
  readonly songStore = new SongStore()
 
 
7
  readonly player: Player
8
  readonly synth: SoundFontSynth
9
 
src/firebase/firebase.ts DELETED
@@ -1,23 +0,0 @@
1
- import { initializeApp } from "firebase/app"
2
- import { connectAuthEmulator, getAuth } from "firebase/auth"
3
- import { connectFirestoreEmulator, getFirestore } from "firebase/firestore"
4
-
5
- const firebaseConfig = {
6
- apiKey: "AIzaSyC5b6N6A1fFxdUyWdZh0RqxvfdM--YD8P0",
7
- authDomain: "signal-9546d.firebaseapp.com",
8
- projectId: "signal-9546d",
9
- storageBucket: "signal-9546d.appspot.com",
10
- messagingSenderId: "312735607354",
11
- appId: "1:312735607354:web:78b487832370b170e32303",
12
- }
13
-
14
- const app = initializeApp(firebaseConfig)
15
-
16
- export const auth = getAuth(app)
17
-
18
- export const firestore = getFirestore(app)
19
-
20
- if (process.env.NODE_ENV !== "production") {
21
- connectAuthEmulator(auth, "http://localhost:9099")
22
- connectFirestoreEmulator(firestore, "localhost", 8080)
23
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/firebase/song.ts DELETED
@@ -1,155 +0,0 @@
1
- import {
2
- addDoc,
3
- Bytes,
4
- collection,
5
- deleteDoc,
6
- DocumentReference,
7
- FirestoreDataConverter,
8
- getDoc,
9
- getDocs,
10
- query,
11
- QueryDocumentSnapshot,
12
- serverTimestamp,
13
- Timestamp,
14
- updateDoc,
15
- where,
16
- } from "firebase/firestore"
17
- import { songFromMidi, songToMidi } from "../common/midi/midiConversion"
18
- import Song from "../common/song"
19
- import { auth, firestore } from "./firebase"
20
-
21
- export interface FirestoreSongData {
22
- createdAt: Timestamp
23
- updatedAt: Timestamp
24
- data?: Bytes
25
- userId: string
26
- }
27
-
28
- export interface FirestoreSong {
29
- name: string
30
- createdAt: Timestamp
31
- updatedAt: Timestamp
32
- dataRef: DocumentReference
33
- userId: string
34
- }
35
-
36
- export const songConverter: FirestoreDataConverter<FirestoreSong> = {
37
- fromFirestore(snapshot, options) {
38
- const data = snapshot.data(options)
39
- return data as FirestoreSong
40
- },
41
- toFirestore(song) {
42
- return song
43
- },
44
- }
45
-
46
- export const songDataConverter: FirestoreDataConverter<FirestoreSongData> = {
47
- fromFirestore(snapshot, options) {
48
- const data = snapshot.data(options)
49
- return data as FirestoreSongData
50
- },
51
- toFirestore(song) {
52
- return song
53
- },
54
- }
55
-
56
- export const songCollection = collection(firestore, "songs").withConverter(
57
- songConverter,
58
- )
59
-
60
- export const songDataCollection = collection(
61
- firestore,
62
- "songData",
63
- ).withConverter(songDataConverter)
64
-
65
- export const loadSong = async (
66
- songSnapshot: QueryDocumentSnapshot<FirestoreSong>,
67
- ) => {
68
- const snapshot = await getDoc(
69
- songSnapshot.data().dataRef.withConverter(songDataConverter),
70
- )
71
- const data = snapshot.data()?.data
72
- if (data === undefined) {
73
- throw new Error("Song data does not exist")
74
- }
75
- const song = songFromMidi(data.toUint8Array())
76
- song.name = songSnapshot.data().name
77
- song.firestoreReference = songSnapshot.ref
78
- song.firestoreDataReference = snapshot.ref
79
- song.isSaved = true
80
- return song
81
- }
82
-
83
- export const createSong = async (song: Song) => {
84
- if (auth.currentUser === null) {
85
- throw new Error("You must be logged in to save songs to the cloud")
86
- }
87
-
88
- const bytes = songToMidi(song)
89
-
90
- const dataDoc = await addDoc(songDataCollection, {
91
- createdAt: serverTimestamp(),
92
- updatedAt: serverTimestamp(),
93
- data: Bytes.fromUint8Array(bytes),
94
- userId: auth.currentUser.uid,
95
- })
96
-
97
- const doc = await addDoc(songCollection, {
98
- name: song.name,
99
- createdAt: serverTimestamp(),
100
- updatedAt: serverTimestamp(),
101
- dataRef: dataDoc,
102
- userId: auth.currentUser.uid,
103
- })
104
-
105
- song.firestoreDataReference = dataDoc
106
- song.firestoreReference = doc
107
- song.isSaved = true
108
- }
109
-
110
- export const updateSong = async (song: Song) => {
111
- if (auth.currentUser === null) {
112
- throw new Error("You must be logged in to save songs to the cloud")
113
- }
114
-
115
- if (
116
- song.firestoreReference === null ||
117
- song.firestoreDataReference === null
118
- ) {
119
- throw new Error("This song is not loaded from the cloud")
120
- }
121
-
122
- const bytes = songToMidi(song)
123
-
124
- await updateDoc(song.firestoreReference, {
125
- updatedAt: serverTimestamp(),
126
- name: song.name,
127
- })
128
-
129
- await updateDoc(song.firestoreDataReference, {
130
- updatedAt: serverTimestamp(),
131
- data: Bytes.fromUint8Array(bytes),
132
- })
133
-
134
- song.isSaved = true
135
- }
136
-
137
- export const deleteSong = async (
138
- song: QueryDocumentSnapshot<FirestoreSong>,
139
- ) => {
140
- if (auth.currentUser === null) {
141
- throw new Error("You must be logged in to save songs to the cloud")
142
- }
143
- await deleteDoc(song.data().dataRef)
144
- await deleteDoc(song.ref)
145
- }
146
-
147
- export const getCurrentUserSongs = async () => {
148
- if (auth.currentUser === null) {
149
- throw new Error("You must be logged in to get songs from the cloud")
150
- }
151
-
152
- return await getDocs(
153
- query(songCollection, where("userId", "==", auth.currentUser.uid)),
154
- )
155
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/components/CloudFileDialog/CloudFileDialog.tsx DELETED
@@ -1,41 +0,0 @@
1
- import { observer } from "mobx-react-lite"
2
- import { useCallback } from "react"
3
- import { Button } from "../../../components/Button"
4
- import {
5
- Dialog,
6
- DialogActions,
7
- DialogContent,
8
- DialogTitle,
9
- } from "../../../components/Dialog"
10
- import { Localized } from "../../../components/Localized"
11
- import { useStores } from "../../hooks/useStores"
12
- import { CloudFileList } from "./CloudFileList"
13
-
14
- export const CloudFileDialog = observer(() => {
15
- const rootStore = useStores()
16
- const {
17
- rootViewStore,
18
- rootViewStore: { openCloudFileDialog },
19
- } = rootStore
20
-
21
- const onClose = useCallback(
22
- () => (rootViewStore.openCloudFileDialog = false),
23
- [rootViewStore],
24
- )
25
-
26
- return (
27
- <Dialog open={openCloudFileDialog} onOpenChange={onClose}>
28
- <DialogTitle>
29
- <Localized default="Files">files</Localized>
30
- </DialogTitle>
31
- <DialogContent>
32
- <CloudFileList />
33
- </DialogContent>
34
- <DialogActions>
35
- <Button onClick={onClose}>
36
- <Localized default="Close">close</Localized>
37
- </Button>
38
- </DialogActions>
39
- </Dialog>
40
- )
41
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/components/CloudFileDialog/CloudFileList.tsx DELETED
@@ -1,176 +0,0 @@
1
- import styled from "@emotion/styled"
2
- import { QueryDocumentSnapshot } from "firebase/firestore"
3
- import ArrowDownward from "mdi-react/ArrowDownwardIcon"
4
- import ArrowDropDown from "mdi-react/ArrowDropDownIcon"
5
- import ArrowUpward from "mdi-react/ArrowUpwardIcon"
6
- import { observer } from "mobx-react-lite"
7
- import { FC, useEffect } from "react"
8
- import { CircularProgress } from "../../../components/CircularProgress"
9
- import { IconButton } from "../../../components/IconButton"
10
- import { Localized } from "../../../components/Localized"
11
- import { Menu, MenuItem } from "../../../components/Menu"
12
- import { FirestoreSong, loadSong } from "../../../firebase/song"
13
- import { setSong } from "../../actions"
14
- import { useLocalization } from "../../hooks/useLocalization"
15
- import { useStores } from "../../hooks/useStores"
16
- import { useTheme } from "../../hooks/useTheme"
17
- import { useToast } from "../../hooks/useToast"
18
- import { CloudFileRow } from "./CloudFileRow"
19
-
20
- const ArrowUp = styled(ArrowUpward)`
21
- width: 1.1rem;
22
- height: 1.1rem;
23
- `
24
-
25
- const ArrowDown = styled(ArrowDownward)`
26
- width: 1.1rem;
27
- height: 1.1rem;
28
- `
29
-
30
- const HeaderCell = styled.div`
31
- display: flex;
32
- align-items: center;
33
- background: ${({ theme }) => theme.backgroundColor};
34
- font-weight: ${({ isSelected }: { isSelected?: boolean }) =>
35
- isSelected ? "bold" : "normal"};
36
- cursor: pointer;
37
- padding: 0 1rem;
38
- box-sizing: border-box;
39
-
40
- &:hover {
41
- background: ${({ theme }) => theme.secondaryBackgroundColor};
42
- }
43
- `
44
-
45
- const NameCell = styled(HeaderCell)`
46
- flex-grow: 1;
47
- `
48
-
49
- const DateCell = styled(HeaderCell)`
50
- width: 12rem;
51
- `
52
-
53
- const MenuCell = styled(HeaderCell)`
54
- width: 4rem;
55
- `
56
-
57
- const Body = styled.div`
58
- max-height: 20rem;
59
- overflow-y: auto;
60
-
61
- tr:hover td {
62
- background: ${({ theme }) => theme.secondaryBackgroundColor};
63
- }
64
- `
65
-
66
- const SortButton: FC<{ sortAscending: boolean }> = ({ sortAscending }) =>
67
- sortAscending ? <ArrowDown /> : <ArrowUp />
68
-
69
- const Container = styled.div``
70
-
71
- const Header = styled.div`
72
- display: flex;
73
- height: 2.5rem;
74
- `
75
-
76
- export const CloudFileList = observer(() => {
77
- const rootStore = useStores()
78
- const { cloudFileStore, rootViewStore } = rootStore
79
- const toast = useToast()
80
- const theme = useTheme()
81
- const localized = useLocalization()
82
- const { isLoading, dateType, files, selectedColumn, sortAscending } =
83
- cloudFileStore
84
-
85
- useEffect(() => {
86
- cloudFileStore.load()
87
- }, [])
88
-
89
- const onClickSong = async (song: QueryDocumentSnapshot<FirestoreSong>) => {
90
- try {
91
- const midiSong = await loadSong(song)
92
- setSong(rootStore)(midiSong)
93
- rootViewStore.openCloudFileDialog = false
94
- } catch (e) {
95
- toast.error((e as Error).message)
96
- }
97
- }
98
- if (isLoading) {
99
- return <CircularProgress />
100
- }
101
-
102
- const sortLabel = (() => {
103
- switch (dateType) {
104
- case "created":
105
- return localized("created-date", "Created")
106
- case "updated":
107
- return localized("modified-date", "Modified")
108
- }
109
- })()
110
-
111
- return (
112
- <Container>
113
- <Header>
114
- <NameCell
115
- onClick={() => {
116
- if (cloudFileStore.selectedColumn === "name") {
117
- cloudFileStore.sortAscending = !cloudFileStore.sortAscending
118
- } else {
119
- cloudFileStore.selectedColumn = "name"
120
- }
121
- }}
122
- isSelected={selectedColumn === "name"}
123
- >
124
- <Localized default="Name">name</Localized>
125
- <div style={{ width: "0.5rem" }}></div>
126
- {selectedColumn === "name" && (
127
- <SortButton sortAscending={sortAscending} />
128
- )}
129
- </NameCell>
130
- <DateCell
131
- onClick={() => {
132
- if (cloudFileStore.selectedColumn === "date") {
133
- cloudFileStore.sortAscending = !cloudFileStore.sortAscending
134
- } else {
135
- cloudFileStore.selectedColumn = "date"
136
- }
137
- }}
138
- isSelected={selectedColumn === "date"}
139
- >
140
- {sortLabel}
141
- <Menu
142
- trigger={
143
- <IconButton
144
- style={{
145
- marginLeft: "0.2em",
146
- }}
147
- >
148
- <ArrowDropDown style={{ fill: theme.secondaryTextColor }} />
149
- </IconButton>
150
- }
151
- >
152
- <MenuItem onClick={() => (cloudFileStore.dateType = "created")}>
153
- <Localized default="Created">created-date</Localized>
154
- </MenuItem>
155
- <MenuItem onClick={() => (cloudFileStore.dateType = "updated")}>
156
- <Localized default="Modified">modified-date</Localized>
157
- </MenuItem>
158
- </Menu>
159
- {selectedColumn === "date" && (
160
- <SortButton sortAscending={sortAscending} />
161
- )}
162
- </DateCell>
163
- <MenuCell></MenuCell>
164
- </Header>
165
- <Body>
166
- {files.map((song) => (
167
- <CloudFileRow
168
- song={song}
169
- dateType={dateType}
170
- onClick={() => onClickSong(song)}
171
- />
172
- ))}
173
- </Body>
174
- </Container>
175
- )
176
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/components/CloudFileDialog/CloudFileRow.tsx DELETED
@@ -1,120 +0,0 @@
1
- import styled from "@emotion/styled"
2
- import { QueryDocumentSnapshot } from "firebase/firestore"
3
- import DotsHorizontalIcon from "mdi-react/DotsHorizontalIcon"
4
- import { observer } from "mobx-react-lite"
5
- import { FC } from "react"
6
- import { IconButton } from "../../../components/IconButton"
7
- import { Localized } from "../../../components/Localized"
8
- import { Menu, MenuItem } from "../../../components/Menu"
9
- import { FirestoreSong } from "../../../firebase/song"
10
- import { useLocalization } from "../../hooks/useLocalization"
11
- import { useStores } from "../../hooks/useStores"
12
- import { useTheme } from "../../hooks/useTheme"
13
- import { useToast } from "../../hooks/useToast"
14
-
15
- const Container = styled.div`
16
- display: flex;
17
- cursor: pointer;
18
- height: 2.5rem;
19
- overflow: hidden;
20
-
21
- &:hover {
22
- background: ${({ theme }) => theme.secondaryBackgroundColor};
23
- }
24
- `
25
-
26
- const Cell = styled.div`
27
- display: flex;
28
- align-items: center;
29
- padding: 0 1rem;
30
- box-sizing: border-box;
31
- `
32
-
33
- const NameCell = styled(Cell)`
34
- overflow: hidden;
35
- flex-grow: 1;
36
- `
37
-
38
- const DateCell = styled(Cell)`
39
- width: 12rem;
40
- flex-shrink: 0;
41
- `
42
-
43
- const MenuCell = styled(Cell)`
44
- width: 4rem;
45
- flex-shrink: 0;
46
- `
47
-
48
- const NoWrapText = styled.span`
49
- white-space: nowrap;
50
- text-overflow: ellipsis;
51
- overflow: hidden;
52
- `
53
-
54
- export interface CloudFileRowProps {
55
- onClick: () => void
56
- song: QueryDocumentSnapshot<FirestoreSong>
57
- dateType: "created" | "updated"
58
- }
59
-
60
- export const CloudFileRow: FC<CloudFileRowProps> = observer(
61
- ({ song, onClick, dateType }) => {
62
- const theme = useTheme()
63
- const toast = useToast()
64
- const localized = useLocalization()
65
- const { cloudFileStore } = useStores()
66
- const date: Date = (() => {
67
- switch (dateType) {
68
- case "created":
69
- return song.data().createdAt.toDate()
70
- case "updated":
71
- return song.data().updatedAt.toDate()
72
- }
73
- })()
74
- const songName =
75
- song.data().name.length > 0
76
- ? song.data().name
77
- : localized("untitled-song", "Untitled song")
78
- const dateStr = date.toLocaleDateString() + " " + date.toLocaleTimeString()
79
- return (
80
- <Container onClick={onClick}>
81
- <NameCell>
82
- <NoWrapText>{songName}</NoWrapText>
83
- </NameCell>
84
- <DateCell>{dateStr}</DateCell>
85
- <MenuCell>
86
- <Menu
87
- trigger={
88
- <IconButton
89
- style={{
90
- marginLeft: "0.2em",
91
- }}
92
- >
93
- <DotsHorizontalIcon
94
- style={{ fill: theme.secondaryTextColor }}
95
- />
96
- </IconButton>
97
- }
98
- >
99
- <MenuItem
100
- onClick={async (e) => {
101
- e.stopPropagation()
102
- try {
103
- await cloudFileStore.deleteSong(song)
104
- toast.info(localized("song-deleted", "Song deleted"))
105
- } catch (e) {
106
- console.error(e)
107
- toast.error(
108
- localized("song-delete-failed", "Song delete failed"),
109
- )
110
- }
111
- }}
112
- >
113
- <Localized default="Delete">delete</Localized>
114
- </MenuItem>
115
- </Menu>
116
- </MenuCell>
117
- </Container>
118
- )
119
- },
120
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/components/FirebaseAuth/StyledFirebaseAuth.tsx DELETED
@@ -1,106 +0,0 @@
1
- // Copy from https://github.com/firebase/firebaseui-web-react/pull/173#issuecomment-1151532176
2
-
3
- import styled from "@emotion/styled"
4
- import { onAuthStateChanged } from "firebase/auth"
5
- import * as firebaseui from "firebaseui"
6
- import { useEffect, useRef, useState } from "react"
7
-
8
- interface Props {
9
- // The Firebase UI Web UI Config object.
10
- // See: https://github.com/firebase/firebaseui-web#configuration
11
- uiConfig: firebaseui.auth.Config
12
- // Callback that will be passed the FirebaseUi instance before it is
13
- // started. This allows access to certain configuration options such as
14
- // disableAutoSignIn().
15
- uiCallback?(ui: firebaseui.auth.AuthUI): void
16
- // The Firebase App auth instance to use.
17
- firebaseAuth: any // As firebaseui-web
18
- }
19
-
20
- const Container = styled.div`
21
- ul.firebaseui-idp-list {
22
- list-style-type: none;
23
- padding: 0;
24
- }
25
-
26
- button.firebaseui-idp-button {
27
- display: flex;
28
- align-items: center;
29
- padding: 0.5rem 1rem;
30
- border-radius: 0.5rem;
31
- border: 1px solid ${({ theme }) => theme.dividerColor};
32
- background: inherit !important;
33
- color: inherit;
34
- min-height: 3rem;
35
- min-width: 12rem;
36
- justify-content: center;
37
- cursor: pointer;
38
-
39
- &:hover {
40
- background: ${({ theme }) => theme.highlightColor} !important;
41
- }
42
- }
43
-
44
- img.firebaseui-idp-icon {
45
- width: 1.5rem;
46
- }
47
-
48
- span.firebaseui-idp-icon-wrapper {
49
- display: flex;
50
- margin-right: 1rem;
51
- }
52
-
53
- span.firebaseui-idp-text.firebaseui-idp-text-short {
54
- display: none;
55
- }
56
-
57
- li.firebaseui-list-item {
58
- margin-bottom: 1rem;
59
- display: flex;
60
- justify-content: center;
61
- }
62
- `
63
-
64
- export const StyledFirebaseAuth = ({
65
- uiConfig,
66
- firebaseAuth,
67
- uiCallback,
68
- }: Props) => {
69
- const [userSignedIn, setUserSignedIn] = useState(false)
70
- const elementRef = useRef(null)
71
-
72
- useEffect(() => {
73
- // Get or Create a firebaseUI instance.
74
- const firebaseUiWidget =
75
- firebaseui.auth.AuthUI.getInstance() ||
76
- new firebaseui.auth.AuthUI(firebaseAuth)
77
-
78
- if (uiConfig.signInFlow === "popup") {
79
- firebaseUiWidget.reset()
80
- }
81
-
82
- // We track the auth state to reset firebaseUi if the user signs out.
83
- const unregisterAuthObserver = onAuthStateChanged(firebaseAuth, (user) => {
84
- if (!user && userSignedIn) {
85
- firebaseUiWidget.reset()
86
- }
87
- setUserSignedIn(!!user)
88
- })
89
-
90
- // Trigger the callback if any was set.
91
- if (uiCallback) {
92
- uiCallback(firebaseUiWidget)
93
- }
94
-
95
- // Render the firebaseUi Widget.
96
- // @ts-ignore
97
- firebaseUiWidget.start(elementRef.current, uiConfig)
98
-
99
- return () => {
100
- unregisterAuthObserver()
101
- firebaseUiWidget.reset()
102
- }
103
- }, [firebaseui, uiConfig])
104
-
105
- return <Container ref={elementRef} />
106
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/components/Navigation/CloudFileMenu.tsx DELETED
@@ -1,244 +0,0 @@
1
- import { observer } from "mobx-react-lite"
2
- import { ChangeEvent, FC } from "react"
3
- import { emptySong } from "../../../common/song"
4
- import { Localized } from "../../../components/Localized"
5
- import { MenuDivider, MenuItem } from "../../../components/Menu"
6
- import { createSong, updateSong } from "../../../firebase/song"
7
- import { openSong, saveSong, setSong } from "../../actions"
8
- import { hasFSAccess, openFile, saveFileAs } from "../../actions/file"
9
- import { useDialog } from "../../hooks/useDialog"
10
- import { useLocalization } from "../../hooks/useLocalization"
11
- import { usePrompt } from "../../hooks/usePrompt"
12
- import { useStores } from "../../hooks/useStores"
13
- import { useToast } from "../../hooks/useToast"
14
- import { FileInput } from "./LegacyFileMenu"
15
-
16
- export const CloudFileMenu: FC<{ close: () => void }> = observer(
17
- ({ close }) => {
18
- const rootStore = useStores()
19
- const { rootViewStore } = rootStore
20
- const toast = useToast()
21
- const prompt = usePrompt()
22
- const dialog = useDialog()
23
- const localized = useLocalization()
24
-
25
- const saveOrCreateSong = async () => {
26
- const { song } = rootStore
27
- if (song.firestoreReference !== null) {
28
- if (song.name.length === 0) {
29
- const text = await prompt.show({
30
- title: localized("save-as", "Save as"),
31
- })
32
- if (text !== null && text.length > 0) {
33
- song.name = text
34
- }
35
- }
36
- await updateSong(song)
37
- toast.success(localized("song-saved", "Song saved"))
38
- } else {
39
- if (song.name.length === 0) {
40
- const text = await prompt.show({
41
- title: localized("save-as", "Save as"),
42
- })
43
- if (text !== null && text.length > 0) {
44
- song.name = text
45
- }
46
- }
47
- await createSong(song)
48
- toast.success(localized("song-created", "Song created"))
49
- }
50
- }
51
-
52
- // true: saved or not necessary
53
- // false: canceled
54
- const saveIfNeeded = async (): Promise<boolean> => {
55
- const { song } = rootStore
56
- if (song.isSaved) {
57
- return true
58
- }
59
-
60
- const res = await dialog.show({
61
- title: localized(
62
- "save-changes",
63
- "Do you want to save your changes to the song?",
64
- ),
65
- actions: [
66
- { title: localized("yes", "Yes"), key: "yes" },
67
- { title: localized("no", "No"), key: "no" },
68
- { title: localized("cancel", "Cancel"), key: "cancel" },
69
- ],
70
- })
71
- switch (res) {
72
- case "yes":
73
- await saveOrCreateSong()
74
- return true
75
- case "no":
76
- return true
77
- case "cancel":
78
- return false
79
- }
80
- }
81
-
82
- const onClickNew = async () => {
83
- close()
84
- try {
85
- if (!(await saveIfNeeded())) {
86
- return
87
- }
88
- const newSong = emptySong()
89
- setSong(rootStore)(newSong)
90
- await createSong(newSong)
91
- toast.success(localized("song-created", "Song created"))
92
- } catch (e) {
93
- toast.error((e as Error).message)
94
- }
95
- }
96
-
97
- const onClickOpen = async () => {
98
- close()
99
- try {
100
- if (!(await saveIfNeeded())) {
101
- return
102
- }
103
- rootViewStore.openCloudFileDialog = true
104
- } catch (e) {
105
- toast.error((e as Error).message)
106
- }
107
- }
108
-
109
- const onClickSave = async () => {
110
- close()
111
- try {
112
- await saveOrCreateSong()
113
- } catch (e) {
114
- toast.error((e as Error).message)
115
- }
116
- }
117
-
118
- const onClickSaveAs = async () => {
119
- const { song } = rootStore
120
- close()
121
- try {
122
- const text = await prompt.show({
123
- title: localized("save-as", "Save as"),
124
- initialText: song.name,
125
- })
126
- if (text !== null && text.length > 0) {
127
- song.name = text
128
- } else {
129
- return
130
- }
131
- await createSong(song)
132
- toast.success(localized("song-saved", "Song saved"))
133
- } catch (e) {
134
- toast.error((e as Error).message)
135
- }
136
- }
137
-
138
- const onClickRename = async () => {
139
- close()
140
- const { song } = rootStore
141
- try {
142
- if (song.name.length === 0) {
143
- const text = await prompt.show({
144
- title: localized("rename", "Rename"),
145
- })
146
- if (text !== null && text.length > 0) {
147
- song.name = text
148
- } else {
149
- return Promise.resolve(false)
150
- }
151
- }
152
- if (song.firestoreReference !== null) {
153
- await updateSong(song)
154
- } else {
155
- await createSong(song)
156
- }
157
- toast.success(localized("song-saved", "Song saved"))
158
- } catch (e) {
159
- toast.error((e as Error).message)
160
- }
161
- }
162
-
163
- const onClickImportLegacy = async (e: ChangeEvent<HTMLInputElement>) => {
164
- close()
165
- try {
166
- await openSong(rootStore)(e.currentTarget)
167
- await saveOrCreateSong()
168
- } catch (e) {
169
- toast.error((e as Error).message)
170
- }
171
- }
172
-
173
- const onClickImport = async () => {
174
- close()
175
- try {
176
- if (!(await saveIfNeeded())) {
177
- return
178
- }
179
- await openFile(rootStore)
180
- await saveOrCreateSong()
181
- } catch (e) {
182
- toast.error((e as Error).message)
183
- }
184
- }
185
-
186
- const onClickExport = async () => {
187
- try {
188
- if (hasFSAccess) {
189
- await saveFileAs(rootStore)
190
- } else {
191
- saveSong(rootStore)()
192
- }
193
- } catch (e) {
194
- toast.error((e as Error).message)
195
- }
196
- }
197
-
198
- return (
199
- <>
200
- <MenuItem onClick={onClickNew}>
201
- <Localized default="New">new-song</Localized>
202
- </MenuItem>
203
-
204
- <MenuDivider />
205
-
206
- <MenuItem onClick={onClickOpen}>
207
- <Localized default="Open">open-song</Localized>
208
- </MenuItem>
209
-
210
- <MenuItem onClick={onClickSave} disabled={rootStore.song.isSaved}>
211
- <Localized default="Save">save-song</Localized>
212
- </MenuItem>
213
-
214
- <MenuItem onClick={onClickSaveAs}>
215
- <Localized default="Save As">save-as</Localized>
216
- </MenuItem>
217
-
218
- <MenuItem onClick={onClickRename}>
219
- <Localized default="Rename">rename</Localized>
220
- </MenuItem>
221
-
222
- <MenuDivider />
223
-
224
- {!hasFSAccess && (
225
- <FileInput onChange={onClickImportLegacy}>
226
- <MenuItem>
227
- <Localized default="Import MIDI file">import-midi</Localized>
228
- </MenuItem>
229
- </FileInput>
230
- )}
231
-
232
- {hasFSAccess && (
233
- <MenuItem onClick={onClickImport}>
234
- <Localized default="Import MIDI file">import-midi</Localized>
235
- </MenuItem>
236
- )}
237
-
238
- <MenuItem onClick={onClickExport}>
239
- <Localized default="Export MIDI file">export-midi</Localized>
240
- </MenuItem>
241
- </>
242
- )
243
- },
244
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/components/Navigation/FileMenuButton.tsx CHANGED
@@ -1,4 +1,3 @@
1
- import CloudOutlined from "mdi-react/CloudOutlineIcon"
2
  import KeyboardArrowDown from "mdi-react/KeyboardArrowDownIcon"
3
  import { observer } from "mobx-react-lite"
4
  import { FC, useCallback, useRef } from "react"
@@ -6,7 +5,6 @@ import { Localized } from "../../../components/Localized"
6
  import { Menu, MenuDivider, MenuItem } from "../../../components/Menu"
7
  import { hasFSAccess } from "../../actions/file"
8
  import { useStores } from "../../hooks/useStores"
9
- import { CloudFileMenu } from "./CloudFileMenu"
10
  import { FileMenu } from "./FileMenu"
11
  import { LegacyFileMenu } from "./LegacyFileMenu"
12
  import { Tab } from "./Navigation"
@@ -15,8 +13,7 @@ export const FileMenuButton: FC = observer(() => {
15
  const rootStore = useStores()
16
  const {
17
  rootViewStore,
18
- exportStore,
19
- authStore: { user },
20
  } = rootStore
21
  const isOpen = rootViewStore.openDrawer
22
  const handleClose = () => (rootViewStore.openDrawer = false)
@@ -45,9 +42,9 @@ export const FileMenuButton: FC = observer(() => {
45
  </Tab>
46
  }
47
  >
48
- {user === null && hasFSAccess && <FileMenu close={handleClose} />}
49
 
50
- {user === null && !hasFSAccess && <LegacyFileMenu close={handleClose} />}
51
 
52
  <MenuDivider />
53
 
 
 
1
  import KeyboardArrowDown from "mdi-react/KeyboardArrowDownIcon"
2
  import { observer } from "mobx-react-lite"
3
  import { FC, useCallback, useRef } from "react"
 
5
  import { Menu, MenuDivider, MenuItem } from "../../../components/Menu"
6
  import { hasFSAccess } from "../../actions/file"
7
  import { useStores } from "../../hooks/useStores"
 
8
  import { FileMenu } from "./FileMenu"
9
  import { LegacyFileMenu } from "./LegacyFileMenu"
10
  import { Tab } from "./Navigation"
 
13
  const rootStore = useStores()
14
  const {
15
  rootViewStore,
16
+ exportStore
 
17
  } = rootStore
18
  const isOpen = rootViewStore.openDrawer
19
  const handleClose = () => (rootViewStore.openDrawer = false)
 
42
  </Tab>
43
  }
44
  >
45
+ {hasFSAccess && <FileMenu close={handleClose} />}
46
 
47
+ {!hasFSAccess && <LegacyFileMenu close={handleClose} />}
48
 
49
  <MenuDivider />
50
 
src/main/components/Navigation/Navigation.tsx CHANGED
@@ -89,7 +89,6 @@ export const IconStyle: CSSProperties = {
89
  export const Navigation: FC = observer(() => {
90
  const {
91
  rootViewStore,
92
- authStore: { user },
93
  router,
94
  } = useStores()
95
 
 
89
  export const Navigation: FC = observer(() => {
90
  const {
91
  rootViewStore,
 
92
  router,
93
  } = useStores()
94
 
src/main/components/Navigation/UserButton.tsx CHANGED
@@ -1,22 +1,12 @@
1
  import { observer } from "mobx-react-lite"
2
  import { FC } from "react"
3
- import { auth } from "../../../firebase/firebase"
4
  import { useStores } from "../../hooks/useStores"
5
  import { UserButtonContent } from "./UserButtonContent"
6
 
7
  export const UserButton: FC = observer(() => {
8
  const {
9
  rootViewStore,
10
- authStore: { user },
11
  } = useStores()
12
 
13
- return (
14
- <UserButtonContent
15
- user={user}
16
- onClickSignIn={() => (rootViewStore.openSignInDialog = true)}
17
- onClickSignOut={async () => {
18
- await auth.signOut()
19
- }}
20
- />
21
- )
22
  })
 
1
  import { observer } from "mobx-react-lite"
2
  import { FC } from "react"
 
3
  import { useStores } from "../../hooks/useStores"
4
  import { UserButtonContent } from "./UserButtonContent"
5
 
6
  export const UserButton: FC = observer(() => {
7
  const {
8
  rootViewStore,
 
9
  } = useStores()
10
 
11
+ return (null)
 
 
 
 
 
 
 
 
12
  })
src/main/components/RootView/RootView.tsx CHANGED
@@ -4,7 +4,6 @@ import { FC } from "react"
4
  import { useStores } from "../../hooks/useStores"
5
  import { ArrangeEditor } from "../ArrangeView/ArrangeEditor"
6
  import { BuildInfo } from "../BuildInfo"
7
- import { CloudFileDialog } from "../CloudFileDialog/CloudFileDialog"
8
  import { ControlSettingDialog } from "../ControlSettingDialog/ControlSettingDialog"
9
  import { ExportDialog } from "../ExportDialog/ExportDialog"
10
  import { ExportProgressDialog } from "../ExportDialog/ExportProgressDialog"
@@ -14,7 +13,6 @@ import { Navigation } from "../Navigation/Navigation"
14
  import { OnBeforeUnload } from "../OnBeforeUnload/OnBeforeUnload"
15
  import { PianoRollEditor } from "../PianoRoll/PianoRollEditor"
16
  import { SettingDialog } from "../SettingDialog/SettingDialog"
17
- import { SignInDialog } from "../SignInDialog/SignInDialog"
18
  import { TempoEditor } from "../TempoGraph/TempoEditor"
19
  import { TransportPanel } from "../TransportPanel/TransportPanel"
20
  import { ArrangeTransposeDialog } from "../TransposeDialog/ArrangeTransposeDialog"
 
4
  import { useStores } from "../../hooks/useStores"
5
  import { ArrangeEditor } from "../ArrangeView/ArrangeEditor"
6
  import { BuildInfo } from "../BuildInfo"
 
7
  import { ControlSettingDialog } from "../ControlSettingDialog/ControlSettingDialog"
8
  import { ExportDialog } from "../ExportDialog/ExportDialog"
9
  import { ExportProgressDialog } from "../ExportDialog/ExportProgressDialog"
 
13
  import { OnBeforeUnload } from "../OnBeforeUnload/OnBeforeUnload"
14
  import { PianoRollEditor } from "../PianoRoll/PianoRollEditor"
15
  import { SettingDialog } from "../SettingDialog/SettingDialog"
 
16
  import { TempoEditor } from "../TempoGraph/TempoEditor"
17
  import { TransportPanel } from "../TransportPanel/TransportPanel"
18
  import { ArrangeTransposeDialog } from "../TransposeDialog/ArrangeTransposeDialog"
src/main/components/SignInDialog/SignInDialog.tsx DELETED
@@ -1,39 +0,0 @@
1
- import { observer } from "mobx-react-lite"
2
- import { FC, useCallback } from "react"
3
- import { useLocalization } from "../../hooks/useLocalization"
4
- import { useStores } from "../../hooks/useStores"
5
- import { useToast } from "../../hooks/useToast"
6
- import { SignInDialogContent } from "./SignInDialogContent"
7
-
8
- export const SignInDialog: FC = observer(() => {
9
- const rootStore = useStores()
10
- const {
11
- rootViewStore,
12
- rootViewStore: { openSignInDialog },
13
- } = rootStore
14
- const toast = useToast()
15
- const localized = useLocalization()
16
-
17
- const onClose = useCallback(
18
- () => (rootViewStore.openSignInDialog = false),
19
- [rootViewStore],
20
- )
21
-
22
- const signInSuccessWithAuthResult = () => {
23
- rootViewStore.openSignInDialog = false
24
- toast.success(localized("success-sign-in", "Successfully signed in"))
25
- }
26
-
27
- const signInFailure = (error: firebaseui.auth.AuthUIError) => {
28
- console.warn(error)
29
- }
30
-
31
- return (
32
- <SignInDialogContent
33
- open={openSignInDialog}
34
- onClose={onClose}
35
- onSuccess={signInSuccessWithAuthResult}
36
- onFailure={signInFailure}
37
- />
38
- )
39
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/components/SignInDialog/SignInDialogContent.tsx DELETED
@@ -1,86 +0,0 @@
1
- import { FC } from "react"
2
- import {
3
- Dialog,
4
- DialogActions,
5
- DialogContent,
6
- DialogTitle,
7
- } from "../../../components/Dialog"
8
- import { StyledFirebaseAuth } from "../FirebaseAuth/StyledFirebaseAuth"
9
-
10
- import styled from "@emotion/styled"
11
- import "firebase/auth"
12
- import { GithubAuthProvider, GoogleAuthProvider } from "firebase/auth"
13
- import { Alert } from "../../../components/Alert"
14
- import { Button } from "../../../components/Button"
15
- import { Localized } from "../../../components/Localized"
16
- import { auth } from "../../../firebase/firebase"
17
-
18
- const BetaLabel = styled.span`
19
- border: 1px solid currentColor;
20
- font-size: 0.8rem;
21
- padding: 0.1rem 0.4rem;
22
- margin-left: 1em;
23
- color: ${({ theme }) => theme.secondaryTextColor};
24
- `
25
-
26
- const Description = styled.div`
27
- margin: 1rem 0 2rem 0;
28
- line-height: 1.5;
29
- `
30
-
31
- export interface SignInDialogContentProps {
32
- open: boolean
33
- onClose: () => void
34
- onSuccess: () => void
35
- onFailure: (error: firebaseui.auth.AuthUIError) => void
36
- }
37
-
38
- export const SignInDialogContent: FC<SignInDialogContentProps> = ({
39
- open,
40
- onClose,
41
- onSuccess,
42
- onFailure,
43
- }) => {
44
- return (
45
- <Dialog open={open} onOpenChange={onClose} style={{ minWidth: "20rem" }}>
46
- <DialogTitle>
47
- <Localized default="Sign in">sign-in</Localized>
48
- <BetaLabel>Beta</BetaLabel>
49
- </DialogTitle>
50
- <DialogContent>
51
- <Alert severity="info">
52
- <Localized default="Since the cloud function is in beta during development, please download and save your important songs frequently.">
53
- cloud-beta-warning
54
- </Localized>
55
- </Alert>
56
- <Description>
57
- <Localized default="By signing in, you can save your music to the cloud and resume composing from anywhere at any time.">
58
- cloud-description
59
- </Localized>
60
- </Description>
61
- <StyledFirebaseAuth
62
- uiConfig={{
63
- signInOptions: [
64
- GoogleAuthProvider.PROVIDER_ID,
65
- GithubAuthProvider.PROVIDER_ID,
66
- ],
67
- callbacks: {
68
- signInSuccessWithAuthResult() {
69
- onSuccess()
70
- return false
71
- },
72
- signInFailure: onFailure,
73
- },
74
- signInFlow: "popup",
75
- }}
76
- firebaseAuth={auth}
77
- />
78
- </DialogContent>
79
- <DialogActions>
80
- <Button onClick={onClose}>
81
- <Localized default="Close">close</Localized>
82
- </Button>
83
- </DialogActions>
84
- </Dialog>
85
- )
86
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/stores/AuthStore.ts DELETED
@@ -1,17 +0,0 @@
1
- import { User } from "firebase/auth"
2
- import { makeObservable, observable } from "mobx"
3
- import { auth } from "../../firebase/firebase"
4
-
5
- export class AuthStore {
6
- user: User | null = null
7
-
8
- constructor() {
9
- makeObservable(this, {
10
- user: observable,
11
- })
12
-
13
- auth.onAuthStateChanged((user) => {
14
- this.user = user
15
- })
16
- }
17
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/stores/CloudFileStore.ts DELETED
@@ -1,65 +0,0 @@
1
- import { QueryDocumentSnapshot } from "@firebase/firestore"
2
- import { orderBy } from "lodash"
3
- import { computed, makeObservable, observable } from "mobx"
4
- import {
5
- FirestoreSong,
6
- deleteSong,
7
- getCurrentUserSongs,
8
- } from "../../firebase/song"
9
- import RootStore from "./RootStore"
10
-
11
- export class CloudFileStore {
12
- isLoading = false
13
- selectedColumn: "name" | "date" = "date"
14
- dateType: "created" | "updated" = "created"
15
- sortAscending = false
16
- _files: QueryDocumentSnapshot<FirestoreSong>[] = []
17
-
18
- constructor(private readonly rootStore: RootStore) {
19
- makeObservable(this, {
20
- isLoading: observable,
21
- selectedColumn: observable,
22
- dateType: observable,
23
- sortAscending: observable,
24
- _files: observable,
25
- files: computed,
26
- })
27
- }
28
-
29
- async load() {
30
- this.isLoading = true
31
- const snapshot = await getCurrentUserSongs()
32
- this._files = snapshot.docs
33
- this.isLoading = false
34
- }
35
-
36
- get files() {
37
- return orderBy(
38
- this._files,
39
- (f) => {
40
- const data = f.data()
41
- switch (this.selectedColumn) {
42
- case "name":
43
- return data.name
44
- case "date":
45
- switch (this.dateType) {
46
- case "created":
47
- return data.createdAt.seconds
48
- case "updated":
49
- return data.updatedAt.seconds
50
- }
51
- }
52
- },
53
- this.sortAscending ? "asc" : "desc",
54
- )
55
- }
56
-
57
- async deleteSong(song: QueryDocumentSnapshot<FirestoreSong>) {
58
- await deleteSong(song)
59
- if (this.rootStore.song.firestoreReference?.id === song.id) {
60
- this.rootStore.song.firestoreReference = null
61
- this.rootStore.song.firestoreDataReference = null
62
- }
63
- await this.load()
64
- }
65
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/main/stores/RootStore.ts CHANGED
@@ -8,8 +8,6 @@ import { MIDIInput, previewMidiInput } from "../services/MIDIInput"
8
  import { MIDIRecorder } from "../services/MIDIRecorder"
9
  import { SoundFontSynth } from "../services/SoundFontSynth"
10
  import ArrangeViewStore from "./ArrangeViewStore"
11
- import { AuthStore } from "./AuthStore"
12
- import { CloudFileStore } from "./CloudFileStore"
13
  import { ControlStore } from "./ControlStore"
14
  import { ExportStore } from "./ExportStore"
15
  import HistoryStore from "./HistoryStore"
@@ -33,8 +31,6 @@ export default class RootStore {
33
  readonly tempoEditorStore = new TempoEditorStore(this)
34
  readonly midiDeviceStore = new MIDIDeviceStore()
35
  readonly exportStore = new ExportStore()
36
- readonly authStore = new AuthStore()
37
- readonly cloudFileStore = new CloudFileStore(this)
38
  readonly settingStore = new SettingStore()
39
  readonly player: Player
40
  readonly synth: SoundFontSynth
 
8
  import { MIDIRecorder } from "../services/MIDIRecorder"
9
  import { SoundFontSynth } from "../services/SoundFontSynth"
10
  import ArrangeViewStore from "./ArrangeViewStore"
 
 
11
  import { ControlStore } from "./ControlStore"
12
  import { ExportStore } from "./ExportStore"
13
  import HistoryStore from "./HistoryStore"
 
31
  readonly tempoEditorStore = new TempoEditorStore(this)
32
  readonly midiDeviceStore = new MIDIDeviceStore()
33
  readonly exportStore = new ExportStore()
 
 
34
  readonly settingStore = new SettingStore()
35
  readonly player: Player
36
  readonly synth: SoundFontSynth