• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import router from '@ohos.router'
17import curves from '@ohos.curves'
18import { BreakpointSystem, BreakPointType } from '../common/BreakpointSystem'
19import { FoodInfo, Category } from '../model/DataModels'
20import { getFoods, getFoodCategories, getSortedFoodData } from '../model/DataUtil'
21import { Records } from './components/DietRecord'
22
23@Component
24struct FoodListItem {
25  private foodItem: FoodInfo
26
27  build() {
28    Navigator({ target: 'pages/FoodDetail' }) {
29      Row() {
30        Image(this.foodItem.image)
31          .objectFit(ImageFit.Contain)
32          .autoResize(false)
33          .height(40)
34          .width(40)
35          .backgroundColor('#FFf1f3f5')
36          .margin({ right: 16 })
37          .borderRadius(6)
38          .sharedTransition(this.foodItem.letter, {
39            duration: 400,
40            curve: curves.cubicBezier(0.2, 0.2, 0.1, 1.0),
41            delay: 100
42          })
43        Text(this.foodItem.name)
44          .fontSize(14)
45        Blank()
46        Text($r('app.string.calorie_with_kcal_unit', this.foodItem.calories.toString()))
47          .fontSize(14)
48      }
49      .height(64)
50      .width('100%')
51    }
52    .params({ foodId: this.foodItem })
53    .margin({ right: 24, left: 32 })
54  }
55}
56
57@Component
58struct ListModeFoods {
59  private foodItems: FoodInfo[] = getSortedFoodData()
60
61  build() {
62    Column() {
63      Text($r("app.string.title_food_list"))
64        .width('100%')
65        .id('foodList')
66        .height(56)
67        .padding({ left: 20 })
68        .backgroundColor('#FF1f3f5')
69        .fontSize(20)
70
71      List() {
72        ForEach(this.foodItems, (item) => {
73          ListItem() {
74            if (item.letter !== undefined) {
75              FoodListItem({ foodItem: item })
76            } else {
77              Text(item)
78                .fontSize(14)
79                .height(48)
80                .margin({ left: 24 })
81                .width('100%')
82            }
83          }
84        })
85      }
86      .layoutWeight(1)
87    }
88  }
89}
90
91@Component
92struct FoodGridItem {
93  private foodItem: FoodInfo
94  private foodItemIndex: number;
95
96  build() {
97    Column() {
98      Image(this.foodItem.image)
99        .objectFit(ImageFit.Contain)
100        .height(152)
101        .sharedTransition(this.foodItem.letter, {
102          duration: 400,
103          curve: curves.cubicBezier(0.2, 0.2, 0.1, 1.0),
104          delay: 100
105        })
106      Row() {
107        Text(this.foodItem.name)
108          .fontSize(14)
109        Blank()
110        Text($r('app.string.calorie_with_kcal_unit', this.foodItem.calories.toString()))
111          .fontSize(14)
112          .fontColor(0x99000000)
113      }
114      .padding({ left: 12, right: 12 })
115      .width('100%')
116      .height(32)
117      .backgroundColor('#E5E5E5')
118    }
119    .id(`foodItem${this.foodItemIndex}`)
120    .height(184)
121    .backgroundColor('#f1f3f5')
122    .clip(new Rect({ width: '100%', height: '100%', radius: 12 }))
123    .onClick(() => {
124      router.push({ url: 'pages/FoodDetail', params: { foodId: this.foodItem } })
125    })
126  }
127}
128
129@Component
130struct FoodGrid {
131  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'
132  private foodItems: FoodInfo[]
133
134  build() {
135    Grid() {
136      ForEach(this.foodItems, (item: FoodInfo, index: number) => {
137        GridItem() {
138          FoodGridItem({ foodItem: item, foodItemIndex: index })
139        }
140      })
141    }
142    .columnsTemplate(new BreakPointType({
143      sm: '1fr 1fr',
144      md: '1fr 1fr 1fr',
145      lg: '1fr 1fr 1fr 1fr'
146    }).getValue(this.currentBreakpoint))
147    .columnsGap(8)
148    .rowsGap(8)
149    .padding({ left: 16, right: 16 })
150  }
151}
152
153@Component
154struct CategoryModeFoods {
155  @State currentTabIndex: number = 0
156  private foodItems: FoodInfo[] = getFoods()
157  private foodCategories: Category[] = getFoodCategories()
158
159  @Builder tabBarItemBuilder(value: Resource, index: number) {
160    Text(value)
161      .fontColor(this.currentTabIndex === index ? 'rgba(0,0,0,0.9)' : 'rgba(0,0,0,0.6)')
162      .fontSize(this.currentTabIndex === index ? 24 : 18)
163      .margin({ top: 2, left: 10, right: 10 })
164      .height(56)
165  }
166
167  build() {
168    Tabs() {
169      TabContent() {
170        FoodGrid({ foodItems: this.foodItems })
171      }.tabBar(this.tabBarItemBuilder($r('app.string.category_all'), 0))
172
173      ForEach(this.foodCategories, (foodCategory: Category, index) => {
174        TabContent() {
175          FoodGrid({ foodItems: this.foodItems.filter(item => (item.categoryId === foodCategory.id)) })
176        }.tabBar(this.tabBarItemBuilder(foodCategory.name, index + 1))
177      })
178    }
179    .animationDuration(0)
180    .barMode(BarMode.Scrollable)
181    .onChange((index) => {
182      this.currentTabIndex = index
183    })
184  }
185}
186
187@Component
188struct FoodsDisplay {
189  @State isCategoryMode: boolean = true
190
191  build() {
192    Stack({ alignContent: Alignment.TopEnd }) {
193      if (this.isCategoryMode) {
194        CategoryModeFoods()
195      } else {
196        ListModeFoods()
197      }
198      Row() {
199        Image($r("app.media.ic_switch"))
200          .height(24)
201          .width(24)
202          .id('switch')
203          .margin({ left: 24, right: 24 })
204      }
205      .height(56)
206      .backgroundColor(this.isCategoryMode ? Color.White : '#F1F3F5')
207      .onClick(() => {
208        this.isCategoryMode = !this.isCategoryMode
209      })
210    }
211  }
212}
213
214@Entry
215@Component
216struct Home {
217  @State currentTabIndex: number = 0
218  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'
219  private breakpointSystem: BreakpointSystem = new BreakpointSystem()
220
221  @Builder bottomBarItemBuilder(name: Resource, icon: Resource, index: number) {
222    Flex({
223      direction: new BreakPointType({
224        sm: FlexDirection.Column,
225        md: FlexDirection.Row,
226        lg: FlexDirection.Column
227      }).getValue(this.currentBreakpoint),
228      justifyContent: FlexAlign.Center,
229      alignItems: ItemAlign.Center
230    }) {
231      Image(icon)
232        .height(24)
233        .width(24)
234        .fillColor(this.getTabBarColor(index))
235      Text(name)
236        .margin(new BreakPointType({
237          sm: { top: 4 },
238          md: { left: 8 },
239          lg: { top: 4 }
240        }).getValue(this.currentBreakpoint))
241        .fontSize(11)
242        .fontColor(this.getTabBarColor(index))
243    }
244    .width('100%')
245    .height('100%')
246    .id(`tabTitle${index}`)
247  }
248
249  aboutToAppear() {
250    this.breakpointSystem.register()
251  }
252
253  aboutToDisappear() {
254    this.breakpointSystem.unregister()
255  }
256
257  build() {
258    Tabs({
259      barPosition: new BreakPointType({
260        sm: BarPosition.End,
261        md: BarPosition.End,
262        lg: BarPosition.Start
263      }).getValue(this.currentBreakpoint)
264    }) {
265      TabContent() {
266        FoodsDisplay()
267      }.tabBar(this.bottomBarItemBuilder($r("app.string.tab_bar_home"), $r("app.media.ic_bottom_home"), 0))
268
269      TabContent() {
270        Records()
271      }.tabBar(this.bottomBarItemBuilder($r("app.string.tab_bar_record"), $r("app.media.ic_bottom_record"), 1))
272    }
273    .vertical(new BreakPointType({ sm: false, md: false, lg: true }).getValue(this.currentBreakpoint))
274    .barWidth(new BreakPointType({ sm: '100%', md: '100%', lg: '56vp' }).getValue(this.currentBreakpoint))
275    .barHeight(new BreakPointType({ sm: '56vp', md: '56vp', lg: '60%' }).getValue(this.currentBreakpoint))
276    .animationDuration(0)
277    .onChange((index) => {
278      this.currentTabIndex = index
279    })
280  }
281
282  private getTabBarColor(index: number) {
283    return this.currentTabIndex == index ? $r('app.color.tab_bar_select_color') : $r('app.color.tab_bar_normal_color')
284  }
285}