basic tab navigation

other things
This commit is contained in:
austinried
2021-06-18 13:00:12 +09:00
parent de5b479c47
commit 0f1e10d50f
16 changed files with 912 additions and 59 deletions

View File

@@ -1,29 +1,80 @@
import React from 'react';
import { Button, View } from 'react-native';
import React, { useEffect, useState } from 'react';
import { Button, TextInput, View, Text } from 'react-native';
import { useRecoilState } from 'recoil';
import { v4 as uuidv4 } from 'uuid';
import md5 from 'md5';
import { musicDb, settingsDb } from '../clients';
import { appSettingsState, serversState } from '../state/settings';
import { DbStorage } from '../storage/db';
import { StackScreenProps } from '@react-navigation/stack';
const DbControls = () => {
const RecreateDbButton: React.FC<{ db: DbStorage, title: string }> = ({ db, title }) => {
const [inProgress, setInProgress] = useState(false);
const recreateMusicDb = async () => {
try { await musicDb.deleteDb(); } catch {}
await musicDb.createDb();
}
const recreateSettingsDb = async () => {
try { await settingsDb.deleteDb(); } catch {}
await settingsDb.createDb();
const recreateDb = async () => {
setInProgress(true);
try{
try { await db.deleteDb(); } catch {}
await db.createDb();
} finally {
setInProgress(false);
}
}
return (
<Button
title={`Recreate ${title} DB`}
onPress={recreateDb}
disabled={inProgress}
/>
)
}
const DbControls = () => {
return (
<View>
<Button
title='Recreate Music DB'
onPress={recreateMusicDb}
/>
<Button
title='Recreate Settings DB'
onPress={recreateSettingsDb}
<RecreateDbButton db={musicDb} title='Music' />
<RecreateDbButton db={settingsDb} title='Settings' />
</View>
);
}
const ServerSettingsView = () => {
const [servers, setServers] = useRecoilState(serversState);
const [appSettings, setAppSettings] = useRecoilState(appSettingsState);
const bootstrapServer = () => {
if (servers.length !== 0) {
return;
}
const id = uuidv4();
const salt = uuidv4();
const address = 'http://demo.subsonic.org';
setServers([{
id, salt, address,
username: 'guest',
token: md5('guest' + salt),
}]);
setAppSettings({
server: id,
});
};
return (
<View>
<Button
title='Add default server'
onPress={bootstrapServer}
/>
{servers.map(s => (
<View key={s.id}>
<Text>{s.address}</Text>
<Text>{s.username}</Text>
</View>
))}
</View>
);
}
@@ -31,6 +82,9 @@ const DbControls = () => {
const SettingsView = () => (
<View>
<DbControls />
<React.Suspense fallback={<Text>Loading...</Text>}>
<ServerSettingsView />
</React.Suspense>
</View>
)

View File

@@ -1,16 +1,11 @@
import md5 from 'md5';
import { atom, selector, useSetRecoilState } from 'recoil';
import { atom, selector, useRecoilValue, useSetRecoilState } from 'recoil';
import { SubsonicApiClient } from '../subsonic/api';
import { MusicDb } from '../storage/music';
import { activeServer } from './settings'
const db = new MusicDb();
const password = 'test';
const salt = 'salty';
const token = md5(password + salt);
const client = new SubsonicApiClient('http://navidrome.home', 'austin', token, salt);
export interface ArtistState {
id: string;
name: string;
@@ -37,7 +32,14 @@ export const artistsState = atom<ArtistState[]>({
export const useUpdateArtists = () => {
const setArtists = useSetRecoilState(artistsState);
const server = useRecoilValue(activeServer);
return async () => {
if (!server) {
return;
}
const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt);
const response = await client.getArtists();
setArtists(response.data.artists.map(i => ({

47
src/state/settings.ts Normal file
View File

@@ -0,0 +1,47 @@
import { atom, DefaultValue, selector } from 'recoil';
import { settingsDb } from '../clients';
import { AppSettings, ServerSettings } from '../storage/settings';
export const serversState = atom<ServerSettings[]>({
key: 'serverState',
default: selector({
key: 'serversState/default',
get: () => settingsDb.getServers(),
}),
effects_UNSTABLE: [
({ onSet }) => {
onSet((newValue) => {
if (!(newValue instanceof DefaultValue)) {
settingsDb.updateServers(newValue);
}
});
}
],
});
export const appSettingsState = atom<AppSettings>({
key: 'appSettingsState',
default: selector({
key: 'appSettingsState/default',
get: () => settingsDb.getApp(),
}),
effects_UNSTABLE: [
({ onSet }) => {
onSet((newValue, oldValue) => {
if (!(newValue instanceof DefaultValue)) {
settingsDb.updateApp(newValue);
}
});
}
],
});
export const activeServer = selector<ServerSettings | undefined>({
key: 'activeServer',
get: ({get}) => {
const appSettings = get(appSettingsState);
const servers = get(serversState);
return servers.find(x => x.id == appSettings.server);
}
});

View File

@@ -9,9 +9,9 @@ export abstract class DbStorage {
this.dbParams = dbParams;
}
// abstract createDb(): Promise<void>
abstract createDb(): Promise<void>
protected async createDb(scope: (tx: Transaction) => void): Promise<void> {
protected async initDb(scope: (tx: Transaction) => void): Promise<void> {
await this.transaction(tx => {
tx.executeSql(`
CREATE TABLE db_version (

View File

@@ -6,7 +6,7 @@ export class MusicDb extends DbStorage {
}
async createDb(): Promise<void> {
super.createDb(tx => {
await this.initDb(tx => {
tx.executeSql(`
CREATE TABLE artists (
id TEXT PRIMARY KEY NOT NULL,

View File

@@ -18,7 +18,7 @@ export class SettingsDb extends DbStorage {
}
async createDb(): Promise<void> {
super.createDb(tx => {
await this.initDb(tx => {
tx.executeSql(`
CREATE TABLE servers (
id TEXT PRIMARY KEY NOT NULL,
@@ -56,32 +56,32 @@ export class SettingsDb extends DbStorage {
return (await this.getServers()).find(x => x.id === id);
}
async addServer(server: ServerSettings): Promise<void> {
await this.executeSql(`
INSERT INTO servers (id, address, username, token, salt)
VALUES (?, ?, ?, ?, ?);
`, [server.id, server.address, server.username, server.token, server.salt]);
}
// async addServer(server: ServerSettings): Promise<void> {
// await this.executeSql(`
// INSERT INTO servers (id, address, username, token, salt)
// VALUES (?, ?, ?, ?, ?);
// `, [server.id, server.address, server.username, server.token, server.salt]);
// }
async removeServer(id: string): Promise<void> {
await this.executeSql(`
DELETE FROM servers
WHERE id = ?;
`, [id]);
}
// async removeServer(id: string): Promise<void> {
// await this.executeSql(`
// DELETE FROM servers
// WHERE id = ?;
// `, [id]);
// }
async updateServer(server: ServerSettings): Promise<void> {
await this.executeSql(`
UPDATE servers SET
address = ?,
username = ?,
token = ?,
salt = ?
WHERE id = ?;
`, [
server.address, server.username, server.token, server.salt,
server.id,
]);
async updateServers(servers: ServerSettings[]): Promise<void> {
await this.transaction((tx) => {
tx.executeSql(`
DELETE FROM servers
`);
for (const s of servers) {
tx.executeSql(`
INSERT INTO servers (id, address, username, token, salt)
VALUES (?, ?, ?, ?, ?);
`, [s.id, s.address, s.username, s.token, s.salt]);
}
});
}
async getApp(): Promise<AppSettings> {