import { util } from '@kit.ArkTS';
import { i18n } from '@kit.LocalizationKit';
import { sceneMap, site } from '@kit.MapKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { geoLocationManager } from '@kit.LocationKit';
import { abilityAccessCtrl, autoFillManager, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit';
const AUTHED = 0;
const TIME_OUT = 100;
// Default longitude and latitude. The following uses the longitude and latitude of Tiananmen, Beijing as an example.
const INIT_LAT = 39.5;
const INIT_LON = 116.2;
const ENGLISH = 'en';
const SIMPLIFIED_CHINESE = 'zh_CN';
const PERMISSIONS: Array<Permissions> = ['ohos.permission.APPROXIMATELY_LOCATION'];
const ADMINISTRATIVE_REGION: Array<string> =
['countryName', 'adminLevel1', 'adminLevel2', 'adminLevel3', 'adminLevel4'];
interface PersonInfo {
name?: string;
phone?: string;
email?: string;
idCard?: string;
region?: string;
stressAddress?: string;
}
interface RequestParam {
requestTag: string;
requestText: string;
}
interface Location {
latitude: number;
longitude: number;
}
// Display the authorization pop-up.
async function reqPermissionsFromUser(permissions: Array<Permissions>,
context: common.UIAbilityContext): Promise<PermissionRequestResult> {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
return await atManager.requestPermissionsFromUser(context, permissions);
}
// Throttle function.
function debounce(func: () => void, wait: number = TIME_OUT): Function {
let timeout: number | null = null;
return () => {
timeout && clearTimeout(timeout);
timeout = setTimeout(() => {
func();
clearTimeout(timeout);
}, wait);
};
}
@Extend(Text)
function textStyle() {
.width(64)
.textAlign(TextAlign.End)
}
@Entry
@Component
struct Index {
@State personInfo: PersonInfo = {};
@State isClicked: boolean = false;
// Whether the user has triggered information input.
private isUserInput: boolean = false;
private location: Location = {
latitude: INIT_LAT,
longitude: INIT_LON,
};
private currentRequestTag: string = '';
private handleAddressChange = (request: RequestParam) => {
return debounce(async () => {
this.autoCompleteAddress(request);
});
};
aboutToAppear() {
reqPermissionsFromUser(PERMISSIONS, getContext(this) as common.UIAbilityContext)
.then((permissionRequestResult: PermissionRequestResult) => {
if (permissionRequestResult.authResults[0] === AUTHED) {
// The API for obtaining location information can be called only under authorization.
geoLocationManager.getCurrentLocation((err, location: geoLocationManager.Location) => {
if (err) {
hilog.error(0x0000, 'testTag', `Failed to get location, code: ${err?.code}, message: ${err?.message}`);
return;
}
hilog.info(0x0000, 'testTag', `Succeeded in obtaining the current location of the user`);
this.location.latitude = location.latitude;
this.location.longitude = location.longitude;
})
}
})
.catch((err: BusinessError) => {
hilog.error(0x0000, 'testTag', `Failed request permissions, code: ${err?.code}, message: ${err?.message}`);
})
}
public isUsLanguage(): boolean {
let result: string = '';
try {
result = i18n.System.getSystemLanguage();
} catch (error) {
hilog.error(0x0000, 'testTag', 'Failed to get system language');
}
return result.toLowerCase() === 'en-latn-us';
}
async autoCompleteAddress(request: RequestParam): Promise<void> {
try {
let params: site.SearchByTextParams = {
query: request.requestText,
// Longitude and latitude to which search results need to be biased.
location: {
latitude: this.location.latitude,
longitude: this.location.longitude
},
language: this.isUsLanguage() ? ENGLISH : SIMPLIFIED_CHINESE,
isChildren: true
};
const result = await site.searchByText(params);
if (result.sites) {
let region: string = '';
let addressComponent = result.sites[0].addressComponent;
// Traverse the administrative region level of the current address.
for (let item of ADMINISTRATIVE_REGION) {
if (addressComponent[item] === undefined) {
break;
}
region += addressComponent[item];
}
// Prevent repeated searches that may lead to inconsistent results.
if (request.requestTag === this.currentRequestTag) {
this.personInfo.region = region;
}
}
} catch (error) {
hilog.error(0x0000, 'testTag', `Failed to search location, code: ${error.code}, message: ${error.message}`);
}
hilog.info(0x0000, 'testTag', 'Succeeded in searching location');
}
onRegionClick(): void {
// After a user selects an administrative region, display only search results from the selected region to prevent prolonged queries.
this.currentRequestTag = util.generateRandomUUID();
let districtSelectOptions: sceneMap.DistrictSelectOptions = {
countryCode: 'CN',
};
sceneMap.selectDistrict(getContext(this), districtSelectOptions).then((data) => {
hilog.info(0x0000, 'testTag', 'SelectDistrict', 'Succeeded in selecting district.');
let region = '';
for (let i = 0; i < data?.districts?.length; i++) {
region += data.districts[i].name;
}
this.personInfo.region = region;
}).catch((err: BusinessError) => {
hilog.error(0x0000, 'testTag', `Failed to select district, code: ${err.code}, message: ${err.message}`);
});
}
searchRegionByAddress(val: string): void {
let tag: string = util.generateRandomUUID();
this.currentRequestTag = tag;
let param: RequestParam = {
requestTag: tag,
requestText: val
}
// For the manual user input scenario, dithering processing is required. For the automatic input scenario of SmartFill, only the query processing is required.
if (this.isUserInput) {
this.handleAddressChange(param)();
} else {
this.autoCompleteAddress(param);
}
}
build() {
Column({ space: 8 }) {
Row({ space: 8 }) {
Text('姓名').textStyle()
TextInput({ text: this.personInfo.name, placeholder: '姓名' })
.layoutWeight(1)
.contentType(ContentType.PERSON_FULL_NAME)
.onChange((val: string) => {
this.personInfo.name = val;
})
}
Row({ space: 8 }) {
Text('联系电话').textStyle()
TextInput({ text: this.personInfo.phone, placeholder: '手机号码' })
.layoutWeight(1)
.contentType(ContentType.PHONE_NUMBER)
.onChange((val: string) => {
this.personInfo.phone = val;
})
}
Row({ space: 8 }) {
Text('身份证号').textStyle()
TextInput({ text: this.personInfo.idCard, placeholder: '身份证信息' })
.layoutWeight(1)
.contentType(ContentType.ID_CARD_NUMBER)
.onChange((val: string) => {
this.personInfo.idCard = val;
})
}
Row({ space: 8 }) {
Text('邮件地址').textStyle()
TextInput({ text: this.personInfo.email, placeholder: '电子邮件信息' })
.layoutWeight(1)
.contentType(ContentType.EMAIL_ADDRESS)
.onChange((val: string) => {
this.personInfo.email = val;
})
}
Row({ space: 8 }) {
Text('所在地区').textStyle()
TextArea({ text: this.personInfo.region, placeholder: '地区信息' })
.layoutWeight(1)
.backgroundColor($r('sys.color.ohos_id_color_card_bg'))
.placeholderColor($r('sys.color.ohos_id_color_text_secondary'))
.fontSize($r('sys.float.ohos_id_text_size_body1'))
.fontColor($r('sys.color.ohos_id_color_text_primary'))
.onClick(() => this.onRegionClick())
.focusable(false)
}
Row({ space: 8 }) {
Text('详细地址').textStyle()
TextInput({ text: this.personInfo.stressAddress, placeholder: '小区门牌信息' })
.layoutWeight(1)
.contentType(ContentType.DETAIL_INFO_WITHOUT_STREET)
.onDidInsert(() => {
// Triggered when a user inputs data through an input method.
this.isUserInput = true;
})
.onDidDelete((val: DeleteValue) => {
// Triggered when a user deletes data through an input method.
if (val?.deleteValue?.length > 0) {
this.isUserInput = true;
}
})
.onChange((val: string) => {
this.personInfo.stressAddress = val;
if (val && val.trim().length > 0) {
this.searchRegionByAddress(val);
} else {
this.currentRequestTag = util.generateRandomUUID();
this.personInfo.region = '';
}
this.isUserInput = false;
})
}
Button('保存')
.width('50%')
.onClick(() => {
if (!this.isClicked) {
this.isClicked = true;
autoFillManager.requestAutoSave(this.getUIContext(), {
onSuccess: () => {
hilog.info(0x0000, 'testTag', 'Succeeded in saving request');
},
onFailure: () => {
hilog.info(0x0000, 'testTag', 'Failed to save request');
}
});
setTimeout(() => {
this.isClicked = false;
}, 2000);
}
})
}
.padding({ left: 16, right: 16 })
.backgroundColor($r('sys.color.ohos_id_color_list_card_bg'))
.alignItems(HorizontalAlign.Center)
.height('100%')
.width('100%')
}
}