1/**
2 * Copyright (c) 2021 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 */
15import ResourceUtil from '../common/ResourceUtil';
16import SearchData from '../model/SearchData';
17import LogUtil from '../../../../../../utils/src/main/ets/default/baseUtil/LogUtil';
18import Log from '../../../../../../utils/src/main/ets/default/baseUtil/LogDecorator';
19import ConfigData from '../../../../../../utils/src/main/ets/default/baseUtil/ConfigData';
20
21interface Info {
22  type: number;
23  text: string;
24}
25
26interface InfoItem {
27  index: number;
28  data: Info;
29}
30
31/**
32 * result component
33 */
34@Component
35export default struct ResultComponent {
36  @Link highlightKeyword: string
37  @State icon: string = ''
38  @State data: SearchData = new SearchData()
39  @State columnSpace: string = '2vp';
40  private TEXT_TYPE_NORMAL = 1
41  private TEXT_TYPE_KEYWORD = 2
42
43  @Builder
44  HighlightText(
45    spans: Info[],
46    fontColor: Color | Resource,
47    fontSize: Resource,
48    highlightFontColor: Color | Resource) {
49
50    Text() {
51      ForEach(spans.map((item1: Info, index1: number) => {
52        let tmpItem: InfoItem = { index: index1, data: item1 };
53        return tmpItem;
54      }), (item: InfoItem) => {
55        if (item.data.type == this.TEXT_TYPE_NORMAL) {
56          Span(item.data.text).fontColor(fontColor).fontSize(fontSize).fontWeight(FontWeight.Medium)
57        } else if (item.data.type == this.TEXT_TYPE_KEYWORD) {
58          Span(item.data.text).fontColor(highlightFontColor).fontSize(fontSize).fontWeight(FontWeight.Regular)
59        }
60      },
61        (item: InfoItem) => item.index.toString()
62      )
63    }
64    .textAlign(TextAlign.Start)
65    .maxLines(3)
66    .textOverflow({ overflow: TextOverflow.Ellipsis })
67  }
68
69  build() {
70    Row() {
71      Image(this.icon)
72        .width($r('app.float.item_icon_size'))
73        .height($r('app.float.item_icon_size'))
74        .margin({ right: $r('app.float.sys_elements_margin_horizontal_l') })
75        .visibility(this.icon ? Visibility.Visible : Visibility.Hidden)
76        .objectFit(ImageFit.Contain);
77
78      Column({ space: this.columnSpace }) {
79        this.HighlightText(
80          this.splitToHighlightText(this.data.keyword),
81          $r('app.color.search_result_text_color'),
82          $r('app.float.search_result_item_title_font_size'),
83          $r('app.color.search_result_text_color_highlight'),
84        )
85
86        if (this.data.summary) {
87          this.HighlightText(
88            this.splitToHighlightText(this.data.summary),
89            $r('sys.color.ohos_id_color_text_secondary'),
90            $r('app.float.search_result_item_summary_font_size'),
91            $r('app.color.search_result_text_color_highlight'),
92          )
93        }
94      }
95      .layoutWeight(1)
96      .alignItems(HorizontalAlign.Start);
97
98      Image("/res/image/ic_settings_arrow.svg")
99        .width($r('app.float.item_arrow_width'))
100        .height($r('app.float.item_icon_size'))
101        .margin({ left: $r('app.float.sys_elements_margin_horizontal_m') })
102        .fillColor($r("sys.color.ohos_id_color_fourth"))
103    }
104    //    .height($r('app.float.search_item_height'))
105    .padding({
106      left: $r('sys.float.ohos_id_card_margin_start'),
107      right: $r('sys.float.ohos_id_card_margin_end')
108    })
109    .flexShrink(0)
110    .alignItems(VerticalAlign.Center)
111    .align(Alignment.Start)
112  }
113
114  aboutToAppear() {
115    ResourceUtil.getString($r('app.float.distance_2')).then(value => this.columnSpace = value);
116  }
117
118  /**
119   * split to highlight text
120   * @param text
121   */
122  splitToHighlightText(text: string): Info[] {
123    let spans: Info[] = []
124
125    let lowerSpans: string[] = text.toLowerCase().split(this.highlightKeyword.toLowerCase())
126    let keywordStartIndex = 0
127    let keywordLength = this.highlightKeyword.length
128
129    for (let i = 0; i < lowerSpans.length; i++) {
130      let normalText = text.substr(keywordStartIndex, lowerSpans[i].length)
131      spans.push({
132        type: this.TEXT_TYPE_NORMAL,
133        text: normalText
134      })
135      LogUtil.debug(ConfigData.TAG + 'ResultComponent splitToHighlightText : i = [' + i + '] push normal : ' +
136      JSON.stringify(normalText));
137
138      // if not at last, append highlight keyword
139      if (i != lowerSpans.length - 1) {
140        keywordStartIndex += lowerSpans[i].length
141        let keywordText = text.substr(keywordStartIndex, keywordLength)
142        spans.push({
143          type: this.TEXT_TYPE_KEYWORD,
144          text: keywordText
145        })
146        LogUtil.debug(ConfigData.TAG + 'ResultComponent splitToHighlightText : i = [' + i + '] push keyword : ' +
147        JSON.stringify(keywordText));
148        keywordStartIndex += keywordLength
149      }
150    }
151
152    return spans
153  }
154}