c77fb700创建于 2025年1月16日历史提交
/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import router from '@ohos.router'
import { BreakpointSystem, BreakPointType } from '../common/BreakpointSystem'
import { FoodInfo, Category } from '../model/DataModels'
import { getFoods, getFoodCategories, getSortedFoodData } from '../model/DataUtil'
import { Records } from './components/DietRecord'

@Component
struct FoodListItem {
  private foodItem: FoodInfo = new FoodInfo()

  build() {
    Navigator({ target: 'pages/FoodDetail' }) {
      Row() {
        Image(this.foodItem.image)
          .objectFit(ImageFit.Contain)
          .autoResize(false)
          .height(40)
          .width(40)
          .backgroundColor('#FFf1f3f5')
          .margin({ right: 16 })
          .borderRadius(6)
          .sharedTransition(JSON.stringify(this.foodItem.id), {
            duration: 400,
            delay: 100,
            curve:Curve.Ease
          })
        Text(this.foodItem.name)
          .fontSize(14)
        Blank()
        Text($r('app.string.calorie_with_kcal_unit', this.foodItem.calories.toString()))
          .fontSize(14)
      }
      .height(64)
      .width('100%')
    }
    .params({ foodId: this.foodItem })
    .margin({ right: 24, left: 32 })
  }
}

@Component
struct ListModeFoods {
  private foodItems: FoodInfo[] = getSortedFoodData() as FoodInfo[]

  build() {
    Column() {
      Text($r("app.string.title_food_list"))
        .width('100%')
        .height(56)
        .padding({ left: 20 })
        .backgroundColor('#FF1f3f5')
        .fontSize(20)

      List() {
        ForEach(this.foodItems, (item: FoodInfo) => {
          ListItem() {
            if (item.letter !== undefined) {
              FoodListItem({ foodItem: item })
            } else {
              Text(item.letter)
                .fontSize(14)
                .height(48)
                .margin({ left: 24 })
                .width('100%')
            }
          }
        })
      }
      .layoutWeight(1)
    }
  }
}

@Component
struct FoodGridItem {
  private foodItem: FoodInfo = new FoodInfo()

  build() {
    Column() {
      Image(this.foodItem.image)
        .objectFit(ImageFit.Contain)
        .height(152)
        .sharedTransition(JSON.stringify(this.foodItem.id), {
          duration: 400,
          delay: 100,
          curve:Curve.Ease
        })
      Row() {
        Text(this.foodItem.name)
          .fontSize(14)
        Blank()
        Text($r('app.string.calorie_with_kcal_unit', this.foodItem.calories.toString()))
          .fontSize(14)
          .fontColor(0x99000000)
      }
      .padding({ left: 12, right: 12 })
      .width('100%')
      .height(32)
      .backgroundColor('#E5E5E5')
    }
    .height(184)
    .backgroundColor('#f1f3f5')
    .clip(new Rect({ width: '100%', height: '100%', radius: 12 }))
    .onClick(() => {
      router.pushUrl({ url: 'pages/FoodDetail', params: { foodId: this.foodItem } })
    })
  }
}

@Component
struct FoodGrid {
  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'
  private foodItems: FoodInfo[] = []

  build() {
    Grid() {
      ForEach(this.foodItems, (item: FoodInfo) => {
        GridItem() {
          FoodGridItem({ foodItem: item })
        }
      })
    }
    .columnsTemplate(new BreakPointType({
      sm: '1fr 1fr',
      md: '1fr 1fr 1fr',
      lg: '1fr 1fr 1fr 1fr'
    }).getValue(this.currentBreakpoint))
    .columnsGap(8)
    .rowsGap(8)
    .edgeEffect(EdgeEffect.Spring)
    .padding({ left: 16, right: 16 })
  }
}

@Component
struct CategoryModeFoods {
  @State currentTabIndex: number = 0
  private foodItems: FoodInfo[] = getFoods()
  private foodCategories: Category[] = getFoodCategories()

  @Builder
  tabBarItemBuilder(value: Resource | string, index: number) : CustomBuilder {
    Text(value)
      .width(58)
      .fontColor(this.currentTabIndex === index ? 'rgba(0,0,0,0.9)' : 'rgba(0,0,0,0.6)')
      .fontSize(this.currentTabIndex === index ? 22 : 18)
      .height(56)
      .padding({ right: 6 })
  }

  build() {
    Tabs() {
      TabContent() {
        FoodGrid({ foodItems: this.foodItems })
      }.tabBar(this.tabBarItemBuilder($r('app.string.category_all'), 0))

      ForEach(this.foodCategories, (foodCategory: Category, index) => {
        TabContent() {
          FoodGrid({ foodItems: this.foodItems.filter(item => (item.categoryId === foodCategory.id)) })
        }.tabBar(this.tabBarItemBuilder(foodCategory.name, index + 1))
      })
    }
    .barWidth(300)
    .barMode(BarMode.Scrollable)
    .onChange((index) => {
      this.currentTabIndex = index
    })
  }
}

@Component
struct FoodsDisplay {
  @State isCategoryMode: boolean = true

  build() {
    Stack({ alignContent: Alignment.TopEnd }) {
      if (this.isCategoryMode) {
        CategoryModeFoods()
      } else {
        ListModeFoods()
      }
      Row() {
        Image($r("app.media.ic_switch"))
          .height(22)
          .width(22)
          .margin({ left: 10, right: 24 })
      }
      .height(56)
      .backgroundColor(this.isCategoryMode ? Color.White : '#F1F3F5')
      .onClick(() => {
        this.isCategoryMode = !this.isCategoryMode
      })
    }
  }
}

@Entry
@Component
struct Home {
  @State currentTabIndex: number = 0
  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm'
  private breakpointSystem: BreakpointSystem = new BreakpointSystem()

  @Builder
  bottomBarItemBuilder(name: Resource, icon: Resource, index: number) {
    Flex({
      direction: new BreakPointType({
        sm: FlexDirection.Column,
        md: FlexDirection.Row,
        lg: FlexDirection.Column
      }).getValue(this.currentBreakpoint),
      justifyContent: FlexAlign.Center,
      alignItems: ItemAlign.Center
    }) {
      Image(icon)
        .height(24)
        .width(24)
        .fillColor(this.getTabBarColor(index))
      Text(name)
        .margin(new BreakPointType({ sm: 4, md: 8, lg: 4 }).getValue(this.currentBreakpoint))
        .fontSize(11)
        .fontColor(this.getTabBarColor(index))
    }
    .width('100%')
    .height('100%')
  }

  aboutToAppear() {
    this.breakpointSystem.register()
  }

  aboutToDisappear() {
    this.breakpointSystem.unregister()
  }

  build() {
    Tabs({
      barPosition: new BreakPointType({
        sm: BarPosition.End,
        md: BarPosition.End,
        lg: BarPosition.Start
      }).getValue(this.currentBreakpoint)
    }) {
      TabContent() {
        FoodsDisplay()
      }.tabBar(this.bottomBarItemBuilder($r("app.string.tab_bar_home"), $r("app.media.ic_bottom_home"), 0))

      TabContent() {
        Records()
      }.tabBar(this.bottomBarItemBuilder($r("app.string.tab_bar_record"), $r("app.media.ic_bottom_record"), 1))
    }
    .vertical(new BreakPointType({ sm: false, md: false, lg: true }).getValue(this.currentBreakpoint))
    .barWidth(new BreakPointType({ sm: '100%', md: '100%', lg: '56vp' }).getValue(this.currentBreakpoint))
    .barHeight(new BreakPointType({ sm: '56vp', md: '56vp', lg: '60%' }).getValue(this.currentBreakpoint))
    .animationDuration(0)
    .onChange((index) => {
      this.currentTabIndex = index
    })
  }

  private getTabBarColor(index: number) {
    return this.currentTabIndex == index ? $r('app.color.tab_bar_select_color') : $r('app.color.tab_bar_normal_color')
  }
}