Skip to content

Commit

Permalink
feat: support multi-language support, theme color, theme mode (#41)
Browse files Browse the repository at this point in the history
* chore: update router

* refactor: component

* feat: carousel

* feat: handle safe area and status bar

* feat: optimize carousel

* feat: use safe area surface

* fix: always splash when reload app

* fix: loss height in web

* fix: screen unmount flash with a hack way

* feat: optimize theme

* feat: use custom surface

* chore: add setting type

* chore: optimize colors

* docs: update badge

* feat: use theme color lang from local setting

* feat: useAppSettings

* chore: rename

* feat: support app setting

* chore: configure yarn timeout

* chore: configure docker host
  • Loading branch information
dribble-njr authored Dec 11, 2024
1 parent 63a48e8 commit 7d3dca6
Show file tree
Hide file tree
Showing 44 changed files with 1,792 additions and 445 deletions.
1 change: 1 addition & 0 deletions .yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
network-timeout 60000
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Imperial Kitchen

[![runs with Expo Go](https://img.shields.io/badge/Runs%20with%20Expo%20Go-000.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000)](https://expo.dev/client)
[![runs with Expo Go](https://img.shields.io/badge/Runs%20with%20Expo%20Go-4630EB.svg?style=flat-square&logo=EXPO&labelColor=white&logoColor=000)](https://expo.dev/client) [![NestJS](https://img.shields.io/badge/NestJS-E0234E.svg?style=flat-square&logo=NestJS&labelColor=white&logoColor=E0234E)](https://nestjs.com/) [![Prisma](https://img.shields.io/badge/Prisma-2D3748.svg?style=flat-square&logo=Prisma&labelColor=white&logoColor=2D3748)](https://www.prisma.io/) [![MySQL](https://img.shields.io/badge/MySQL-4479A1.svg?style=flat-square&logo=MySQL&labelColor=white&logoColor=4479A1)](https://www.mysql.com/) [![Redis](https://img.shields.io/badge/Redis-DC382D.svg?style=flat-square&logo=Redis&labelColor=white&logoColor=DC382D)](https://redis.io/)

[中文版](README_ZH.md)

Expand All @@ -9,20 +9,13 @@ A food ordering app for family kitchen.
## Features

- [x] Auth: JWT Login, register, logout.
- [x] Multi-language support, theme color, theme mode.
- [ ] Browse menus:View all kinds of food and their details, including images, descriptions and prices.
- [ ] Order food:Choose food and add it to shopping cart.
- [ ] Recipe: Generate recipes.
- [ ] Profile: View personal information, order history, virtual coins.
- [ ] AI assistant: Ask questions about the menu.

## Usage

- fe: Use [`Expo`](https://expo.dev/) to develop cross platform app.
- server: Use [`Nest`](https://nestjs.com/) develop server interface.
- database: Use [`MySQL`](https://www.mysql.com/).
- ORM: [`Prisma`](https://www.prisma.io/).
- others: Use `TypeScript` and `yarn` to manage monorepo.

## Contributing

To develop Expo, you should read [Tools for development](https://docs.expo.dev/develop/tools/) firstly.
Expand Down
11 changes: 2 additions & 9 deletions README_ZH.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 御膳房

[![runs with Expo Go](https://img.shields.io/badge/Runs%20with%20Expo%20Go-000.svg?style=flat-square&logo=EXPO&labelColor=f3f3f3&logoColor=000)](https://expo.dev/client)
[![runs with Expo Go](https://img.shields.io/badge/Runs%20with%20Expo%20Go-4630EB.svg?style=flat-square&logo=EXPO&labelColor=white&logoColor=000)](https://expo.dev/client) [![NestJS](https://img.shields.io/badge/NestJS-E0234E.svg?style=flat-square&logo=NestJS&labelColor=white&logoColor=E0234E)](https://nestjs.com/) [![Prisma](https://img.shields.io/badge/Prisma-2D3748.svg?style=flat-square&logo=Prisma&labelColor=white&logoColor=2D3748)](https://www.prisma.io/) [![MySQL](https://img.shields.io/badge/MySQL-4479A1.svg?style=flat-square&logo=MySQL&labelColor=white&logoColor=4479A1)](https://www.mysql.com/) [![Redis](https://img.shields.io/badge/Redis-DC382D.svg?style=flat-square&logo=Redis&labelColor=white&logoColor=DC382D)](https://redis.io/)

[English Version](README.md)

Expand All @@ -9,20 +9,13 @@
## 特性

- [x] 认证:JWT 登录、注册、登出。
- [x] 多语言支持、主题色、主题模式。
- [ ] 浏览菜单:查看所有食物及其详情,包括图片、描述和价格。
- [ ] 点餐:选择食物并添加到购物车。
- [ ] 菜谱:支持生成菜谱。
- [ ] 个人中心:查看个人信息、订单历史、虚拟货币。
- [ ] AI 助手:询问菜单相关问题。

## 技术栈

- 前端:[`Expo`](https://expo.dev/) 跨端框架;
- 后端:[`Nest`](https://nestjs.com/)
- 数据库:[`MySQL`](https://www.mysql.com/)
- ORM:[`Prisma`](https://www.prisma.io/)
- 其他:`TypeScript``yarn`

## 贡献

开发 Expo 应用前,请先阅读 [开发工具](https://docs.expo.dev/develop/tools/)
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"icon": "./assets/images/icon.png",
"scheme": "imperial-kitchen",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/app/(app)/(tabs)/menu/recipe.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RecipePage } from '@/app/modules/dishes/pages/recipe';
import RecipePage from '@/app/modules/dishes/pages/recipe';

export default function Recipe() {
return <RecipePage />;
Expand Down
199 changes: 194 additions & 5 deletions apps/mobile/app/(app)/(tabs)/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,199 @@
import ParallaxScrollView from '@/components/ParallaxScrollView';
import { Text } from 'react-native-paper';
import { Surface } from '@/components';
import { useColorScheme } from 'react-native';
import { List, Menu, IconButton, Snackbar, Icon } from 'react-native-paper';
import { Language, Languages } from '@/types';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useAppSetting } from '@/hooks/useAppSetting';
import { ColorName, Colors } from '@/constants/Colors';

export default function ProfileScreen() {
const colorScheme = useColorScheme();
const { t } = useTranslation();
const [message, setMessage] = useState({ visible: false, content: '' });

const { setting, updateSetting } = useAppSetting();

const [display, setDisplay] = useState({
color: false,
language: false,
theme: false
});

const themeColors = Colors[setting?.theme === 'auto' ? colorScheme ?? 'light' : setting?.theme ?? 'light'];

return (
<ParallaxScrollView>
<Text>个人详情</Text>
</ParallaxScrollView>
<Surface style={{ flex: 1 }}>
<Surface elevation={0}>
<List.AccordionGroup>
<List.Accordion id="1" title={t('appearance')} left={(props) => <List.Icon {...props} icon="palette" />}>
<List.Item
title={t('language')}
description={t('changeLanguage')}
left={(props) => <List.Icon {...props} icon="translate" />}
right={(props) => (
<Menu
visible={display.language}
onDismiss={() => setDisplay({ ...display, language: false })}
anchor={
<IconButton {...props} icon="pencil" onPress={() => setDisplay({ ...display, language: true })} />
}
>
<Menu.Item
title="System"
trailingIcon={setting?.language === 'auto' ? 'check' : undefined}
onPress={() => {
updateSetting({ language: 'auto' });
setDisplay({ ...display, language: false });
}}
/>
{Object.entries(Languages).map((lang) => (
<Menu.Item
key={lang[0]}
title={`${lang[0]} / ${lang[1]}`}
trailingIcon={setting?.language === lang[0] ? 'check' : undefined}
onPress={() => {
updateSetting({
language: lang[0] as Language
});
setDisplay({ ...display, language: false });
}}
/>
))}
</Menu>
)}
/>
<List.Item
title={t('mode')}
description={t('changeMode')}
left={(props) => (
<List.Icon
{...props}
icon={
setting?.theme === 'auto'
? 'theme-light-dark'
: setting?.theme === 'light'
? 'weather-sunny'
: 'weather-night'
}
/>
)}
right={(props) => (
<Menu
visible={display.theme}
onDismiss={() => setDisplay({ ...display, theme: false })}
anchor={
<IconButton {...props} icon="pencil" onPress={() => setDisplay({ ...display, theme: true })} />
}
>
<Menu.Item
title={t('system')}
leadingIcon="theme-light-dark"
trailingIcon={setting?.theme === 'auto' ? 'check' : undefined}
onPress={() => {
updateSetting({ theme: 'auto' });
setDisplay({ ...display, theme: false });
}}
/>
<Menu.Item
title={t('lightMode')}
leadingIcon="weather-sunny"
trailingIcon={setting?.theme === 'light' ? 'check' : undefined}
onPress={() => {
updateSetting({ theme: 'light' });
setDisplay({ ...display, theme: false });
}}
/>
<Menu.Item
title={t('darkMode')}
leadingIcon="weather-night"
trailingIcon={setting?.theme === 'dark' ? 'check' : undefined}
onPress={() => {
updateSetting({ theme: 'dark' });
setDisplay({ ...display, theme: false });
}}
/>
</Menu>
)}
/>
<List.Item
title={t('color')}
description={t('changeColor')}
left={(props) => (
<List.Icon
{...props}
icon="palette-swatch-variant"
color={
Colors[setting?.theme === 'auto' ? colorScheme ?? 'light' : setting?.theme ?? 'light'][
setting?.color ?? 'default'
]?.primary
}
/>
)}
right={(props) => (
<Menu
visible={display.color}
onDismiss={() => setDisplay({ ...display, color: false })}
anchor={
<IconButton {...props} icon="pencil" onPress={() => setDisplay({ ...display, color: true })} />
}
>
{Object.keys(Colors.light).map((color) => (
<Surface
key={color}
elevation={0}
style={{
width: '100%',
flexDirection: 'row',
alignItems: 'center'
}}
>
<Surface
elevation={0}
style={{
padding: 4,
marginLeft: 8,
borderRadius: 16,
backgroundColor: color !== setting?.color ? undefined : themeColors[color]?.primary
}}
>
<Icon
size={24}
source="palette"
color={
color !== setting?.color
? themeColors[color as ColorName]?.primary
: themeColors[color as ColorName].onPrimary
}
/>
</Surface>

<Menu.Item
key={color}
title={t(color)}
onPress={() => {
updateSetting({
color: color as ColorName
});
setDisplay({ ...display, color: false });
}}
/>
</Surface>
))}
</Menu>
)}
/>
</List.Accordion>
</List.AccordionGroup>
</Surface>

<Snackbar
visible={message.visible}
onDismiss={() => setMessage({ ...message, visible: false })}
onIconPress={() => setMessage({ ...message, visible: false })}
>
{message.content}
</Snackbar>
</Surface>
);
}
4 changes: 3 additions & 1 deletion apps/mobile/app/(app)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ export default function AppLayout() {
if (!accessToken) {
// On web, static rendering will stop here as the user is not authenticated
// in the headless Node process that the pages are rendered in.
return <Redirect href="/guide" />;
return <Redirect href="/(guide)/guide" />;
}

console.log('AppLayout');

return (
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
Expand Down
1 change: 0 additions & 1 deletion apps/mobile/app/(guide)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Stack } from 'expo-router';
export default function GuideLayout() {
return (
<Stack
initialRouteName="guide"
screenOptions={{
animation: 'slide_from_right',
header: (props) => <StackHeader navProps={props} children={undefined} />
Expand Down
10 changes: 3 additions & 7 deletions apps/mobile/app/(guide)/create-kitchen.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import CaptchaInput from '@/components/CaptchaInput';
import FieldInput from '@/components/FieldInput';
import ParallaxScrollView from '@/components/ParallaxScrollView';
import PasswordInput from '@/components/PasswordInput';
import { ThemedView } from '@/components/ThemedView';
import { UserService } from '@/service';
import { RegisterAdminDTO } from '@imperial-kitchen/types';
import { Formik } from 'formik';
import { useTranslation } from 'react-i18next';
import { Alert } from 'react-native';
import { Button, Text } from 'react-native-paper';
import { Surface, CaptchaInput, FieldInput, PasswordInput, ParallaxScrollView } from '@/components';
import * as Yup from 'yup';

export default function CreateKitchen() {
Expand Down Expand Up @@ -40,7 +36,7 @@ export default function CreateKitchen() {

return (
<ParallaxScrollView>
<ThemedView className="flex-1 flex w-full gap-2 justify-between">
<Surface className="flex-1 flex w-full gap-2 justify-between">
<Text className="text-2xl font-bold mb-4">{t('createKitchen.title')}</Text>

<Formik
Expand Down Expand Up @@ -79,7 +75,7 @@ export default function CreateKitchen() {
</>
)}
</Formik>
</ThemedView>
</Surface>
</ParallaxScrollView>
);
}
Loading

0 comments on commit 7d3dca6

Please sign in to comment.