Beginner: Controlling Brightness in Harmony OS Lite wearable - Huawei Developers

Introduction
Harmony OS is a future-proof distributed operating system open to you as part of the initiatives for all-scenario strategy, adaptable to mobile office, fitness and health, social communication, and media entertainment, to name a few. Unlike a legacy operating system that runs on a standalone device, Harmony OS is built on a distributed architecture designed based on a set of system capabilities. It can run on a wide range of device forms, including smartphones, tablets, wearables, smart TVs and head units.
In this article, we will create simple Lite wearable JS application to control the brightness of wearable.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Requirements
1) DevEco IDE
2) Lite wearable simulator
Implementation
First page, index.hml contains basic UI component showing list of predefined brightness values in percentage.
HTML:
<div class="container">
<image class= "image" src='/common/brightness_control.png' ></image>
<text class="title">
Brightness Control
</text>
<list class="showList">
<list-item class="showListItem" for="{{(index, value) in listData}}" tid="id">
<text class="content" onclick="onItemClick(value)">
{{value}}
</text>
<div class="divider"></div>
</list-item>
</list>
</div>
Here, we have placed brightness_control.png image in common directory.
index.css has style defined for the page.
CSS:
.container {
flex-direction: column;
justify-content: center;
align-items: center;
left: 0px;
top: 0px;
background-color: #192841;
width: 454px;
height: 454px;
}
.image {
width: 64px;
height: 64px;
justify-content: center;
margin-bottom: 15px;
margin-left: 10px;
margin-top: 20px;
}
.showList {
flex-direction: column;
width: 300px;
margin-bottom: 10px;
margin-top: 10px;
height: 250px;
}
.showListItem {
flex-direction: column;
align-items: center;
width: 300px;
background-color: #192841;
height: 80px;
}
.title {
font-size: 30px;
}
.content {
margin-bottom: 10px;
margin-top: 10px;
}
.divider {
width: 454px;
height: 2px;
margin-bottom: 10px;
margin-top: 10px;
background-color: lightgrey;
}
Firstly, we need to import the brightness module.
Code:
import brightness from '@system.brightness';
Once user selects predefined brightness value from list, we will call brightness.setValue(value). The value is an integer ranging from 1 to 255.
JavaScript:
setBrightness() {
let _brigtenessValue = this.brigtenessValue;
brightness.setValue({
value: _brigtenessValue,
success: function(){
console.log('handling set brightness success.');
},
fail: function(data, code){
console.log('handling set brightness value fail, code:' + code + ', data: ' + data);
},
});
}
To set screen brightness adjustment mode, we will call brightness.setValue().The value can be 0 or 1.
0: The screen brightness is manually adjusted.
1: The screen brightness is automatically adjusted.
JavaScript:
setBrightnessMode(modeValue) {
brightness.setMode({
mode: modeValue,
success: function(){
console.log('handling set mode success.');
},
fail: function(data, code){
console.log('handling set mode fail, code:' + code + ', data: ' + data);
},
});
}
Code snippet for app.js
JavaScript:
import brightness from '@system.brightness';
export default {
data: {
listData: ['Auto Mode' , '10%', '30%', '50%', '75%', '100%'],
brigtenessValue : 1,
AUTO_MODE : 1,
MANUAL_MODE : 0,
},
onItemClick(value) {
console.log(value);
if(value === 'Auto Mode') {
this.setBrightnessMode(this.AUTO_MODE);
}
else {
this.setBrightnessMode(this.MANUAL_MODE);
let valueInt = parseInt(value.substring(0, value.length -1));
this.brigtenessValue = 255 * (value/100);
this.setBrightness();
}
},
setBrightnessMode(modeValue) {
brightness.setMode({
mode: modeValue,
success: function(){
console.log('handling set mode success.');
},
fail: function(data, code){
console.log('handling set mode fail, code:' + code + ', data: ' + data);
},
});
},
setBrightness() {
let _brigtenessValue = this.brigtenessValue;
brightness.setValue({
value: _brigtenessValue,
success: function(){
console.log('handling set brightness success.');
},
fail: function(data, code){
console.log('handling set brightness value fail, code:' + code + ', data: ' + data);
},
});
},
}
Tips and Tricks
If you are using simulator for development, you can check the changed brightness value by clicking hamburger menu.
Conclusion
In this article, we have learnt how to create simple app to control Brightness of wearable device. You only need one touch to change current display brightness to one of the predefined values or select the "Auto Brightness" mode.
References
Harmony Official document:
Document
developer.harmonyos.com
Harmony OS JS API
Read In Forum

Related

How to integrate Account kit in Quick App

More information like this, you can visit HUAWEI Developer Forum​
Original link: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201346068348190148&fid=0101188387844930001
I have written series of article on Quick App. If you are new to Quick App, refer my previous articles.
Quick App set up
A Novice Journey Towards Quick App ( Part 2 )
A Novice Journey Towards Quick App ( Part 3 )
In this article, we can learn to integrate the Account kit in Quick App.
Introduction
Huawei Account kit helps to login to applications easily and quickly. Once application access account information, user do not need to enter the details like email, name, profile picture etc. It reduces the user time, once the user sign in with trusted Huawei Account kit, then no need to verify email or phone number.
Follow the steps.
1. Create project (refer Quick App Part 1)
2. Design Sign in screen
Configuration in AGC
1. Sign in in to AppGallery and select My projects.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
2. Click Add project.
3. Click Add app in General information tab and set Data storage location.
Note: App Id is very important.
4.Enable Account kit in Manage APIs.
5. Sign in to Huawei Developer using developer id, then click Console.
6. Select Huawei ID in App services page.
7. Now generate certificate in the Quick App IDE(Tools-> Certificate)
8. Once Certificate is creation is done copy the release folder certificates to debug folder. If there is already certificates remove it and copy from release folder.
9. Find the app from the list of app in which the Huawei ID service will be configured, then click Update.
10. Add the certificate and click Submit.
Now let us come to coding.
Add the service.account in manifest.json file
Import the service account in script.
Code:
import account from '@service.account'
Code:
<template>
<div class="container">
<div class="item-container">
<input type="button" class="btn" onclick="useAuthor" value="Login using token mode" />
</div>
<div class="item-container">
<input type="button" class="btn" onclick="getsign" value="Get Account Info" />
</div>
<div class="item-container">
<input type="button" class="btn" onclick="loginByCodeMode" value="Login using authorization code mode" />
</div>
<div class="item-container">
<input type="button" class="btn" onclick="checkUserSession" value="Check user session" />
</div>
<div class="page-title-wrap">
<text class="result" style="color: #000000;" > {{ result }}</text>
</div>
</div>
</template>
<style>
.container{
flex: 1;
flex-direction: column;
}
.page-title-wrap {
padding-top: 50px;
padding-bottom: 80px;
justify-content: center;
}
.result{
padding-top: 30px;
padding-bottom: 30px;
padding-left: 40px;
padding-right: 40px;
border-color: #bbbbbb;
color: #bbbbbb;
}
.btn {
height: 80px;
text-align: center;
border-radius: 5px;
margin-right: 40px;
margin-left: 40px;
margin-bottom: 30px;
color: #ffffff;
font-size: 30px;
background-color: #ff0f1b;
}
.item-container {
margin-top: 30px;
margin-right: 40px;
margin-left: 40px;
flex-direction: column;
}
</style>
<script>
import account from '@service.account'
import prompt from '@system.prompt'
export default {
data: {
componentName: 'account Kit',
componentData: {},
fetchData: '',
attoken: '',
accode:'',
sign: '',
result: ''
},
onInit() {
this.$page.setTitleBar({text: 'Account Kit',
textColor: '#ffffff',
backgroundColor: '#ff0f1b',
menu: false
});
this.componentData = this.$t('Account Kit');
// this.result = 'HI';
},
getsign: function () {
var that = this;
account.getProfile({
appid: "YOUR_APP_ID",
token: that.attoken,
success: function (ret) {
that.result = JSON.stringify(ret)
},
fail: function (erromsg, errocode) {
prompt.showToast({ message: 'getprofile fail --- ' + errocode + ':' + erromsg });
}
})
},
useAuthor: function () {
var that = this;
account.authorize({
appid: "YOUR_APP_ID",
type: "token",
scope: "scope.baseProfile",
state: 5,
redirectUri: "http://www.example.com/",
success: function (ret) {
that.attoken = ret.accessToken;
that.result = JSON.stringify(ret)
},
fail: function (erromsg, errocode) {
prompt.showToast({ message: 'authorize fail --- ' + errocode + ':' + erromsg });
}
})
},
// Login using Authorization Code
checkUserSession: function () {
account.checkUserSession({
success: function (data2) {
console.log('handling success profile: ' + JSON.stringify(data2));
},
fail: function (data, code) {
console.log('handling fail, code =' + code);
}
});
},
loginByCodeMode: function() {
var that = this;
account.authorize({
appid: "YOUR_APP_ID",
type: "code",
scope: "scope.baseProfile",
state:5,
redirectUri: "http://www.example.com/",
success: function (ret) {
that.atcode = ret.code;
console.log(that.componentData.result + JSON.stringify(ret));
that.result = JSON.stringify(ret)
},
fail: function (erromsg, errocode) {
prompt.showToast({ message: 'authorize fail --- ' + errocode + ':' + erromsg });
console.log({message: 'authorize fail --- ' + errocode + ':' + erromsg});
}
})
}
}
</script>
Result
Conclusion
In this article we have learnt how to integrate the Account kit in Quick App. In upcoming article, I will come up with new concept.
Reference
Account kit official document
https://developer.huawei.com/consumer/en/doc/development/quickApp-Guides/quickapp-enable-account-kit
What is the best advantage of Quick app compare to other like ionic, ReactNative

Integrating Huawei Scan-Kit in Flutter

Introduction
HUAWEI Scan Kit scans and parses all major 1D and 2D barcodes as well as generates barcodes to help you quickly build barcode scanning functions into your apps. Scan Kit automatically detects, magnifies, and recognizes barcodes from a distance, and also can scan a very small barcode in the same way. It works even in suboptimal situations, such as under dim lighting or when the barcode is reflective, dirty, blurry, or printed on a cylindrical surface. Huawei Scan kit has a higher scanning success rate.
There are three type of scan type.
1. Default View
2. Customized View
3. Multiprocessor Camera
1. Default View: In Default View mode, Scan Kit scans the barcodes using the camera or from images in the album. You do not need to worry about designing a UI as Scan Kit provides one.
2. Customized View: In Customized View mode, you do not need to worry about developing the scanning process or camera control. Scan Kit will do all these tasks for you. However, you will need to customize the scanning UI according to the customization options that Flutter Scan Plugin provides. This can also be easily completed based on the sample code below.
3. Multiprocessor Camera: Multiprocessor Camera Mode is used to recognize multiple barcodes simultaneously from the scanning UI or from the gallery. Scanning results will be returned as a list and during the scanning, the scanned barcodes will be caught by rectangles and their values will be shown on the scanning UI. In Multiprocessor Camera mode, you do not need to worry about developing the scanning process or camera control. Scan Kit will do all these tasks for you. However, you will need to customize the scanning UI according to the customization options that Flutter Scan Plugin provides.
In this article, we will learn Default view and Customized view.
Follow the steps
Step 1: Register as a Huawei Developer.
Step 2: Download Scan Flutter package and decompress it.
Step 3: Add dependencies pubspec.yaml. Change path according to your downloaded path.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Step 4: After adding the dependencies, click on Pub get.
Step 5: Navigate to any of the *.dart file and click on Get dependencies.
Step 6: Build Flutter sample Application.
Code:
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:huawei_scan/HmsScanLibrary.dart';
import 'item_list.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Scan Kit Demo',
theme: ThemeData(
primarySwatch: Colors.red,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Scan Kit'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/backgrond.jpg"),
fit: BoxFit.cover,
)),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: () async {
DefaultViewRequest request = new DefaultViewRequest(
scanType: HmsScanTypes.AllScanType);
ScanResponse response =
await HmsScanUtils.startDefaultView(request);
setState(() {
var resultScan = response.originalValue;
var codeFormatScan = response.scanType;
var resultTypeScan = response.scanTypeForm;
print("Result" +
resultTypeScan.toString() +
" " +
codeFormatScan.toString() +
" " +
resultScan);
Fluttertoast.showToast(
msg: "Result: "+ resultScan,
toastLength: Toast.LENGTH_LONG,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.black,
textColor: Colors.white,
fontSize: 16.0
);
Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Result" +resultScan),
));
});
},
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
margin: EdgeInsets.all(10.0),
alignment: Alignment(0, 1),
padding: EdgeInsets.all(15.0),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(25)),
child: Text(
'Default View',
style: new TextStyle(color: Colors.white),
),
),
),
InkWell(
onTap: () async {
CustomizedViewRequest request = new CustomizedViewRequest(scanType: HmsScanTypes.AllScanType);
await HmsCustomizedView.startCustomizedView(request);
},
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
margin: EdgeInsets.all(10.0),
alignment: Alignment(0, 1),
padding: EdgeInsets.all(15.0),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(25)),
child: Text(
'Customized View',
style: new TextStyle(color: Colors.white),
),
),
),
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductList()),
);
},
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
margin: EdgeInsets.all(10.0),
alignment: Alignment(0, 1),
padding: EdgeInsets.all(15.0),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(25)),
child: Text(
'Generate QR code',
style: new TextStyle(color: Colors.white),
),
),
)
],
),
),
),
);
}
customizedView() async {
var responseList = [];
ScanResponse response =
await HmsCustomizedView.startCustomizedView(
CustomizedViewRequest(
scanType: HmsScanTypes.AllScanType,
continuouslyScan: false,
isFlashAvailable: true,
flashOnLightChange: false,
customizedCameraListener: (ScanResponse response) {
//pause();
setState(() {
responseList.add(response);
});
//resume();
},
customizedLifeCycleListener:
(CustomizedViewEvent lifecycleStatus) {
debugPrint("Customized View LifeCycle Listener: " +
lifecycleStatus.toString());
if (lifecycleStatus == CustomizedViewEvent.onStart) {
Future.delayed(const Duration(seconds: 5), () async {
// switchLightOnLightStatus();
});
}
},
));
setState(() {
var resultScan = response.originalValue;
var codeFormatScan = response.scanType;
var resultTypeScan = response.scanTypeForm;
print("Result" +
resultTypeScan.toString() +
" " +
codeFormatScan.toString() +
" " +
resultScan);
Fluttertoast.showToast(
msg: "Result: "+ resultScan,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
);
});
}
}
More details, you can check https://forums.developer.huawei.com/forumPortal/en/topic/0203436830890850132

Obtaining Device Information in Harmony OS Lite wearable

Introduction
Harmony OS is a future-proof distributed operating system open to you as part of the initiatives for the all-scenario strategy, adaptable to mobile office, fitness and health, social communication, and media entertainment, to name a few. Unlike a legacy operating system that runs on a standalone device, Harmony OS is built on a distributed architecture designed based on a set of system capabilities. It can run on a wide range of device forms, including smartphones, tablets, wearables, smart TVs and head units.
In this article, we will create simple lite wearable JS application to obtain device information.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Requirements
1) DevEco IDE
2) Lite wearable simulator
Implementation
First page, index.hml contains <swiper> container that enables the switch of child components.
Code:
<swiper class="container" index="{{index}}">
<div class="swiper-item item1">
<text class="title">BRAND</text>
<text class="subtitle">{{brand}}</text>
<div class="seperator" ></div>
<text class="title">MANUFACTURER</text>
<text class="subtitle">{{manufacturer}}</text>
<div class="seperator" ></div>
<text class="title">MODEL</text>
<text class="subtitle">{{model}}</text>
</div>
<div class="swiper-item item2">
<text class="title">PRODUCT</text>
<text class="subtitle">{{product}}</text>
<div class="seperator" ></div>
<text class="title">LANGUAGE</text>
<text class="subtitle">{{language}}</text>
<div class="seperator" ></div>
<text class="title">REGION</text>
<text class="subtitle">{{region}}</text>
</div>
<div class="swiper-item item3">
<text class="title">SCREEN SHAPE</text>
<text class="subtitle">{{shape}}</text>
<div class="seperator" ></div>
<text class="title">SCREEN DENSITY</text>
<text class="subtitle">{{screendensity}}</text>
<div class="seperator" ></div>
<text class="title">DIMENSION</text>
<text class="subtitle">{{dimension}}</text>
</div>
</swiper>
index.css has style defined for the page.
Code:
.container {
left: 0px;
top: 0px;
width: 454px;
height: 454px;
}
.swiper-item {
width: 454px;
height: 454px;
flex-direction: column;
justify-content: center;
align-items: center;
}
.item1 {
background-color: #007dff;
}
.item2 {
background-color: #cc0000;
}
.item3 {
background-color: #41ba41;
}
.title {
font-size:30px;
justify-content: center;
}
.subtitle {
font-size:30px;
color: lightgrey;
margin: 15px;
justify-content: center;
}
.seperator {
height: 1px;
width: 454px;
margin-bottom: 5px;
margin-top: 5px;
background-color: white;
}
To obtain the device information, we will call device.info()
Code:
device.getInfo({
success: function(data) {
console.log('success get device info brand:' + data.brand);
_this.brand = data.brand;
_this.manufacturer = data.manufacturer;
_this.model = data.model;
_this.language = data.language;
_this.product = data.product;
_this.region = data.region;
_this.screendensity = data.screenDensity;
_this.shape = data.screenShape;
_this.dimension = data.windowWidth + ' X ' + data.windowHeight;
},
fail: function(data, code) {
console.log('fail get device info code:'+ code + ', data: ' + data);
},
});
Code Snippet of index.js
Code:
import device from '@system.device';
export default {
data: {
brand: '--',
manufacturer: '--',
language: '--',
model: '--',
product: '--',
region: '--',
dimension: '--',
screendensity: 0,
shape : '--'
}
,
onInit(){
let _this = this;
device.getInfo({
success: function(data) {
console.log('success get device info brand:' + data.brand);
_this.brand = data.brand;
_this.manufacturer = data.manufacturer;
_this.model = data.model;
_this.language = data.language;
_this.product = data.product;
_this.region = data.region;
_this.screendensity = data.screenDensity;
_this.shape = data.screenShape;
_this.dimension = data.windowWidth + ' X ' + data.windowHeight;
},
fail: function(data, code) {
console.log('fail get device info code:'+ code + ', data: ' + data);
},
});
}
}
Tips and Tricks
Not all the information can be obtained on simulator. Hence it is recommended to use physical Harmony OS wearable watch.
Conclusion
In this article, we learnt how easily we can obtain wearable device information such as brand, product, device dimension, density, etc.
References
Harmony OS JS API :
Document
developer.harmonyos.com
Harmony Official document -
Document
developer.harmonyos.com
Very useful

Huawei Smart Watch – Using Compass + Location to make Qibla Finder Application Development using JS on HUAWEI DevEco Studio (HarmonyOS)

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Article Introduction
In this article we will develop Qibla finder application for Huawei Smart Watch device using Huawei DevEco Studio (HarmonyOS). We will fetch Location and Compass API’s of HarmonyOS JS language to develop Application.
1. Create New Project
Let’s create Smart Watch Project and choosing ability template, Wearable and Empty Feature Ability (JS)
Define project name, package name and relevant directory where you want to save your project.
2. Preparing Files and Permission
Let’s first add images and permissions which we will use for project.
All project images will be under common/images folder, check below screenshot.
Next we need to add permissions for Internet and Location under config.json file.
JSON:
"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.LOCATION",
"reason": "get Qibla direction",
"usedScene": {
"ability": [
"default"
],
"when": "always"
}
}
]
3. Compass Development
In Compass screen development we will cover Location permission, Location fetching, location error and compass degree value.
Let’s start development without wasting more time.
Styling:
index.css:
CSS:
.stack {
width: 454px;
height: 454px;
justify-content: center;
background-color: whitesmoke;
}
.container {
background-color: whitesmoke;
}
.compass-container {
display: flex;
justify-content: center;
align-items: center;
left: 0px;
top: 0px;
width: 454px;
height: 454px;
background-color: whitesmoke;
}
.container-location-loading{
background-image: url('/common/images/background.png');
flex-direction: column;
padding-top: 0px;
padding-bottom: 0px;
height: 456px;
width: 456px;
}
.error-container {
background-image: url('/common/images/background.png');
padding-top: 0px;
padding-bottom: 0px;
height: 456px;
width: 100%;
}
.location_loading{
object-fit:contain;
height: 456px;
width: 292px;
}
.column{
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
}
.needle{
left: 0px;
top: 0px;
width: 220px;
height: 220px;
background-color: transparent;
z-index:99;
}
.compass, .compass2{
left: 0px;
top: 0px;
width: 220px;
height: 220px;
background-color: transparent;
z-index:98;
}
.qibla_style{
display: flex;
left: 0px;
top: 0px;
width: 220px;
height: 220px;
background-color: transparent;
z-index:100000;
}
.error_title{
display: flex;
color: red;
width: 100%;
height: 100%;
justify-content: center;
align-content: center;
text-align: center;
font-size: 24px;
}
.button-container{
display: flex;
flex-direction: row;
justify-content: center;
align-content: space-around;
position: absolute;
bottom: 10px;
}
Layout:
Location Loading Animation:
Code:
<stack if="{{isLocationLoading === true && isLocationError === false}}" class="container-location-loading">
<image src="../../common/images/location_animation.gif" class="location_loading" />
</stack>
Location Loading Output:
Location Error and Retry:
Code:
<stack if="{{isLocationLoading === false && isLocationError === true}}" class="error-container">
<text class="error_title">Location not fetch. Try again</text>
<div class="button-container">
<button type="circle" icon="/common/images/exit.png" onclick="exit"></button>
<button type="circle" icon="/common/images/refresh.png" onclick="retry"></button>
</div>
</stack>
Location Error Output:
Compass UI:
Code:
<stack class="compass-container" if="{{isLocationLoading === false && isLocationError === false}}">
<stack class="compass" style="transform:{{compass_transform}}">
<div class="needle" style="transform:{{needle_transform}}">
<image src="/common/images/needle.png"></image>
</div>
<div class="compass" >
<image src="/common/images/compass.png"></image>
</div>
</stack>
<div class="qibla_style">
<image src="/common/images/qibla.png"></image>
</div>
</stack>
Compass UI Output:
JS code:
Structural - Code:
Code:
import sensor from '@system.sensor';
import brightness from '@system.brightness';
import geolocation from '@system.geolocation';
import app from '@system.app';
export default {}
Data:
Code:
data: {
compass_transform: "rotate(0deg)",
needle_transform: "rotate(0deg)",
isLocationLoading: true,
isLocationError: false,
}
Common - Code:
Code:
onReady() {
this.setBrightnessKeepScreenOn();
},
onInit() {
this.initLocationCompass();
},
exit(){
app.terminate();
},
retry(){
this.isLocationLoading = true;
this.isLocationError = false;
this.initLocationCompass();
},
onDestroy() {
sensor.unsubscribeCompass();
},
// Setting the screen to be steady on
setBrightnessKeepScreenOn: function () {
brightness.setKeepScreenOn({
keepScreenOn: true,
success: function () {
console.log("handling set keep screen on success")
},
fail: function (data, code) {
console.log("handling set keep screen on fail, code:" + code);
}
});
},
onBackPress() {
sensor.unsubscribeCompass();
}
Location Fetching - Code:
Code:
initLocationCompass(){
var _this = this;
this.locationLoading().then(result => {
console.info("Location: " + result);
_this.loadCompass(result);
_this.isLocationLoading = false;
_this.isLocationError = false;
}, error => {
console.info("Location: error ->" + error);
_this.isLocationLoading = false;
_this.isLocationError = true;
});
},
locationLoading() {
return new Promise(function (resolve, reject) {
return geolocation.getLocation({
success: function (data) {
console.log('success get location data. latitude:' + data.latitude + 'long:' + data.longitude);
return resolve({
latitude: data.latitude,
longitude: data.longitude
});
},
fail: function (data, code) {
console.log('fail to get location. code:' + code + ', data:' + data);
return reject({
error: 'fail to get location. code:' + code + ', data:' + data
});
},
});
});
},
Compass - Code:
Code:
loadCompass(coordinates = {
latitude: 24.7136,
longitude: 46.6753
}) {
var _this = this;
var qiblaDirection = parseFloat(this.qibla(coordinates));
console.log("compass: qiblaDirection: " + qiblaDirection);
_this.needle_transform = "rotate(" + qiblaDirection + "deg)";
sensor.subscribeCompass({
success: function (ret) {
var direction = ret.direction;
var compassDirection = (360 - direction);
_this.compass_transform = "rotate(" + compassDirection + "deg)";
console.log("compass: compassDirection: " + direction);
},
fail: function (data, code) {
console.error('compass: subscribe compass fail, code: ' + code + ', data: ' + data);
},
});
},
Qibla Direction - Code:
Code:
qibla(coordinates) {
const makkah = {
latitude: 21.42252,
longitude: 39.82621
};
const term1 = Math.sin(this.degreesToRadians(makkah.longitude) - this.degreesToRadians(coordinates.longitude));
const term2 = Math.cos(this.degreesToRadians(coordinates.latitude)) * Math.tan(this.degreesToRadians(makkah.latitude));
const term3 = Math.sin(this.degreesToRadians(coordinates.latitude)) * Math.cos(this.degreesToRadians(makkah.longitude) - this.degreesToRadians(coordinates.longitude));
const angle = Math.atan2(term1, term2 - term3);
return this.unwindAngle(this.radiansToDegrees(angle));
},
degreesToRadians(degrees) {
return degrees * Math.PI / 180.0;
},
radiansToDegrees(radians) {
return radians * 180.0 / Math.PI;
},
normalizeToScale(number, max) {
return number - max * Math.floor(number / max);
},
unwindAngle(angle) {
return this.normalizeToScale(angle, 360.0);
},
Compass Screen Notes:
To manage Layout, we need to use <stack> to overlap UI component in layers. First we need to fetch location data and identify the Qibla direction in degree. And call Compass JS API to get compass degree and manage the UI accordingly.
4. Result
Tips and Tricks:
Requesting some data from internet, you must need to add Internet permission in config.json file.
Fetching Location data, you must need to add Internet Permission in config.json file.
Use Dev Eco Studio Previewer to check the screen layout and design. Previewer is developer friendly to Hot release changes on fly.
For better management of big application it’s a good practice to centralize you common scripts and common style in common folder. Add images folder for complete application images.
In JS script when you make some variable, in callback functions you can store the reference of this to some variable and then call reference variable. Like var _this = this.
References:
HarmonyOS JS API Official Documentation: click here
Geographic Location Documentation: click here
Sensor Documentation: click here
Conclusion:
Developers can able to fetch user location data and compass data to make Qibla finder application. While developing application for HarmonyOS developer can get benefit for both JS and JAVA language.
Original Source

Huawei Smart Watch – Fetch Location to make Prayer times calculation Application Development using JS on HUAWEI DevEco Studio (HarmonyOS)

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Article Introduction
In this article we will develop Prayer Times application for Huawei Smart Watch device using Huawei DevEco Studio (HarmonyOS). We will fetch Location using HarmonyOS JS language API’s and use some of the npm libraries (adhan, moment, moment-timezone, tz-lookup) to develop complete Real world Prayer Times Calculation Application.
1. Create New Project
Let’s create Smart Watch Project and choosing ability template, Empty Ability (JS)
Define project name, package name and relevant directory where you want to save your project. Choose the Device type “wearable” for which we are developing the application.
2. Preparing Files and Permission
Let’s first add images and permissions which we will use for project.
All project images will be under common/images folder, check below screenshot.
Next we need to add Location and Internet permissions under config.json file.
Code:
"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.LOCATION",
"reason": "get user location to show prayer time",
"usedScene": {
"ability": [
"default"
],
"when": "always"
}
}
]
3. NPM libraries installation
We need to install following NPM libraries in the application:
adhan
moment
moment-timezone
tz-lookup
First we need to open the terminal under our DevEco studio project.
We need to change directory to entry folder.
Code:
cd entry
Now we need to install all the required libraries for our project.
Code:
npm i adhan moment moment-timezone tz-lookup -s
After installation our package.json file look like below:
Code:
{
"dependencies": {
"adhan": "^4.1.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.33",
"tz-lookup": "^6.1.25"
}
}
4. Prayer Time App Development
In Prayer time screen development we will cover Location permission, Location fetching, location error layout, prayer timer screen and today all prayers dialog screen.
Let’s start development without wasting more time.
Styling:
index.css: (Common screen styling)
Code:
/* common styling */
.container {
background-color: black;
justify-content: center;
}
.container-sub {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
padding-top: 24px;
}
.container-location-loading {
flex-direction: column;
padding-top: 0px;
padding-bottom: 0px;
height: 456px;
width: 456px;
}
.column {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
background-color: transparent;
}
.row {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 80%;
height: 25px;
background-color: transparent;
}
.title {
text-align: center;
display: flex;
font-size: 16px;
}
.center {
text-align: center;
}
.location_loading {
object-fit: contain;
height: 456px;
width: 240px;
text-align: center;
align-items: center;
}
.current_time {
font-size: 18px;
text-align: center;
}
.mosque {
margin-top: 5px;
text-align: center;
fit-original-size: true;
}
.prayer_name {
text-align: center;
font-size: 16px;
margin-top: 2px;
margin-bottom: 5px;
}
.remaining_timer {
text-align: center;
font-size: 14px;
}
.button-circle {
background-color: transparent;
}
index.css: (Prayer BG & Color styling)
Code:
/* prayer BG & Color */
.prayer_bg {
background-position: top center;
background-size: 100% 280px;
}
.fajr_bg {
background-image: url('/common/images/prayer_bg/fajr.jpg');
}
.fajr_color {
background-color: #30170d;
}
.dhuhr_bg {
background-image: url('/common/images/prayer_bg/dhuhr.jpg');
}
.dhuhr_color {
background-color: #021823;
}
.asr_bg {
background-image: url('/common/images/prayer_bg/asr.jpg');
}
.asr_color {
background-color: #172B34;
}
.maghrib_bg {
background-image: url('/common/images/prayer_bg/maghrib.jpg');
}
.maghrib_color {
background-color: #010101;
}
.isha_bg {
background-image: url('/common/images/prayer_bg/isha.jpg');
}
.isha_color {
background-color: #082C44;
}
.night_bg {
background-image: url('/common/images/prayer_bg/night.jpg');
}
.night_color {
background-color: #131C39;
}
index.css: (Dialog styling)
Code:
/*Dialog styling*/
.dialog-main {
width: 100%;
}
.dialog-div {
display: flex;
flex-direction: column;
align-items: center;
}
.inner-txt {
width: 100%;
height: 300px;
flex-direction: column;
align-items: center;
}
.inner-btn {
width: 100%;
height: 154px;
align-items: center;
}
index.css: (List styling)
Code:
/*list styling*/
.list-wrapper {
width: 100%;
flex-direction: column;
}
.list-items {
width: 100%;
flex-direction: column;
padding: 0 24px;
}
.item-wrapper {
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
height: 34px;
margin: 8px 0;
}
.item-icon-wrapper {
width: 24px;
}
.item-icon {
width: 24px;
height: 24px;
object-fit: contain;
}
.item-name-description-wrapper {
flex-direction: column;
justify-content: center;
align-items: center;
flex-grow: 1;
flex-shrink: 1;
width: 50%;
margin-right: 24px;
margin-left: 24px;
}
.item-name {
text-align: left;
color: #DBFFFFFF;
font-size: 16px;
}
.item-description {
text-align: left;
opacity: 0.75;
color: #99FFFFFF;
font-size: 14px;
}
.item-right-part-wrapper {
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
.item-right-text {
margin-right: 4px;
margin-left: 8px;
font-size: 14px;
opacity: 0.75;
}
.item-right-arrow {
width: 12px;
height: 24px;
object-fit: contain;
}
.line {
stroke-width: 1px;
width: 100%;
background-color: #33FFFFFF;
margin-left: 40px;
}
index.css: (Birds animation styling)
Code:
/* Birds animation */
.birds_animation {
object-fit: scale-down;
position: absolute;
top: 0px;
left: -200px;
animation-name: Fly;
animation-duration: 15s;
animation-timing-function: ease;
animation-iteration-count: infinite;
}
@keyframes Fly {
from {
transform: translateX(-200px);
}
to {
transform: translateX(1000px);
}
}
Layout:
Index.hml: (Location Loading Animation)
Code:
<div if="{{ isLocationLoading === true }}" class="container-location-loading">
<image src="common/images/location_animation.gif" class="location_loading"/>
</div>
Index.hml: (Location Loading Output):
Index.hml: (Location Error & Retry)
Code:
<div class="column" if="{{ isLocationLoading === false && isLocationError === true }}">
<text class="title">Location not fetch, please try again later.</text>
</div>
Index.hml: (Prayer timer UI)
Code:
<div class="container-sub prayer_bg {{ prayer_bg }}" if="{{ isLocationLoading === false && isLocationError === false }}">
<image src="common/images/birds.gif" class="birds_animation"></image>
<text class="current_time">{{ currentTime }}</text>
<image class="mosque" src="common/images/mosque.png"></image>
<text class="prayer_name">{{nextPrayer}} {{nextPrayerTime}}</text>
<text if="{{isShowTargetTime}}" class="remaining_timer">{{nextPrayerRemaining}}</text>
<button type="circle" class="button-circle"
ontouchend="showPrayer" icon="common/images/down-arrow.png"></button>
</div>
Index.hml: (Prayer timer UI Output)
Index.hml: (Dialog all Prayer times)
Code:
<dialog id="simpledialog" class="dialog-main">
<div class="dialog-div {{ dialog_bg }}">
<button type="circle" class="button-circle"
ontouchend="closePrayer" icon="common/images/close.png"></button>
<div class="inner-txt">
<div class="prayers-list">
<div class="list-items-left">
<list class="list-wrapper" initialindex="{{ initial_index_value }}">
<block for="{{ prayer_data }}">
<list-item class="list-items" @click="changeList($idx)" id="{{ $idx }}">
<div class="item-wrapper">
<div class="item-icon-wrapper">
<image class="item-icon" src="{{ $item.item_icon }}"></image>
</div>
<div class="item-name-description-wrapper">
<text class="item-name">{{ $item.item_name }}</text>
<text class="item-description">{{ $item.item_description }}</text>
</div>
<div class="item-right-part-wrapper">
<image class="item-right-arrow" src="common/images/right_arrow_dark_mode.png"></image>
</div>
</div>
<div class="divider-line">
<divider class="line"></divider>
</div>
</list-item>
</block>
</list>
</div>
</div>
</div>
</div>
</dialog>
Index.hml: (Dialog all Prayer times Ouput)
Index.hml: (Complete code)
Code:
<div class="container {{ (isLocationLoading === false) ? 'column' : '' }}">
<div if="{{ isLocationLoading === true }}" class="container-location-loading">
<image src="common/images/location_animation.gif" class="location_loading"/>
</div>
<div class="column" if="{{ isLocationLoading === false && isLocationError === true }}">
<text class="title">Location not fetch, please try again later.</text>
</div>
<div class="container-sub prayer_bg {{ prayer_bg }}" if="{{ isLocationLoading === false && isLocationError === false }}">
<image src="common/images/birds.gif" class="birds_animation"></image>
<text class="current_time">{{ currentTime }}</text>
<image class="mosque" src="common/images/mosque.png"></image>
<text class="prayer_name">{{nextPrayer}} {{nextPrayerTime}}</text>
<text if="{{isShowTargetTime}}" class="remaining_timer">{{nextPrayerRemaining}}</text>
<button type="circle" class="button-circle"
ontouchend="showPrayer" icon="common/images/down-arrow.png"></button>
</div>
<dialog id="simpledialog" class="dialog-main">
<div class="dialog-div {{ dialog_bg }}">
<button type="circle" class="button-circle"
ontouchend="closePrayer" icon="common/images/close.png"></button>
<div class="inner-txt">
<div class="prayers-list">
<div class="list-items-left">
<list class="list-wrapper" initialindex="{{ initial_index_value }}">
<block for="{{ prayer_data }}">
<list-item class="list-items" @click="changeList($idx)" id="{{ $idx }}">
<div class="item-wrapper">
<div class="item-icon-wrapper">
<image class="item-icon" src="{{ $item.item_icon }}"></image>
</div>
<div class="item-name-description-wrapper">
<text class="item-name">{{ $item.item_name }}</text>
<text class="item-description">{{ $item.item_description }}</text>
</div>
<div class="item-right-part-wrapper">
<image class="item-right-arrow" src="common/images/right_arrow_dark_mode.png"></image>
</div>
</div>
<div class="divider-line">
<divider class="line"></divider>
</div>
</list-item>
</block>
</list>
</div>
</div>
</div>
</div>
</dialog>
</div>
JS code:
index.js: (Structural - Code)
Code:
import geolocation from '@system.geolocation';
import adhan from 'adhan';
import moment from 'moment';
import tz from 'moment-timezone';
var tzlookup = require("tz-lookup");
const TAG = 'app_log [index]';
export default {}
index.js: (Data - Code)
Code:
data: {
config: {
isTesting: true,
locationCoordinates: {
"latitude": 24.65382908421087,
"longitude": 46.73552629355017
},
timeZone: "Asia/Riyadh",
fakeDateTime: "2021-06-12 18:13:01"
},
prayer_data: [
{
item_id: "fajr",
item_icon: "common/images/prayer_icon/fajr.png",
item_name: 'Fajr',
item_description: ''
},
{
item_id: "dhuhr",
item_icon: "common/images/prayer_icon/dhuhr.png",
item_name: 'Dhuhr',
item_description: ''
},
{
item_id: "asr",
item_icon: "common/images/prayer_icon/asr.png",
item_name: 'Asr',
item_description: ''
},
{
item_id: "maghrib",
item_icon: "common/images/prayer_icon/maghrib.png",
item_name: 'Maghrib',
item_description: ''
},
{
item_id: "isha",
item_icon: "common/images/prayer_icon/isha.png",
item_name: 'Isha',
item_description: ''
},
],
defaultPrayerSetting: {
allowNotification: false,
prayerSetting: {
Madhab: 'Shafi',
calculationMethod: 'UmmAlQura',
adjustments: {
fajr: "0",
sunrise: "0",
dhuhr: "0",
asr: "0",
maghrib: "0",
isha: "0"
}
}
},
initial_index_value: 2,
isLocationError: false,
isLocationLoading: true,
locationCoordinates: null,
currentTime: null,
timeUpdateTimer: null,
nextPrayer: 'Night',
nextPrayerTime: '',
nextPrayerRemaining: '',
isShowTargetTime: true,
date: moment().toDate(),
prayer_bg: "night_bg",
dialog_bg: "night_color"
},
index.js: (Common - Code)
Code:
onInit() {
console.log(TAG + 'onInit');
if(this.config.isTesting === true){
this.locationCoordinates = this.config.locationCoordinates
moment.tz.setDefault(this.config.timeZone);
this.date = moment(this.config.fakeDateTime).toDate();
}
this.currentTime = moment(this.date).format('ddd LT');
this.timeUpdateTimer = setInterval(this.updateTimer, 2000);
},
onReady() {
console.log(TAG + 'onReady');
var _this = this;
if (this.locationCoordinates !== null) {
setTimeout(() => {
_this.calculatePrayerTime();
_this.isLocationLoading = false;
_this.isLocationError = false;
}, 4000);
} else {
this.locationLoading().then(result => {
_this.locationCoordinates = result;
console.info(TAG + "Location: " + result);
_this.calculatePrayerTime();
_this.isLocationLoading = false;
_this.isLocationError = false;
}, error => {
console.info(TAG + "Location: error ->" + error);
_this.isLocationLoading = false;
_this.isLocationError = true;
});
}
},
onShow() {
console.log(TAG + 'onShow');
},
onDestroy() {
console.log(TAG + 'onDestroy');
clearInterval(this.timeUpdateTimer);
this.timeUpdateTimer = null;
clearInterval(this.countDownTimer);
this.countDownTimer = null;
},
updateTimer() {
this.currentTime = moment().format('ddd LT');
if(this.config.isTesting === true){
this.currentTime = moment(this.config.fakeDateTime).format('ddd LT');
}
},
index.js: (Dialog - Code)
Code:
showPrayer(e) {
this.$element('simpledialog').show();
},
closePrayer(e) {
this.$element('simpledialog').close();
},
index.js: (Location Fetching - Code)
Code:
locationLoading() {
return new Promise(function (resolve, reject) {
return geolocation.getLocation({
success: function (data) {
console.log('success get location data. latitude:' + data.latitude + 'long:' + data.longitude);
return resolve({
latitude: data.latitude,
longitude: data.longitude
});
},
fail: function (data, code) {
console.log('fail to get location. code:' + code + ', data:' + data);
return reject({
error: 'fail to get location. code:' + code + ', data:' + data
});
},
});
});
},
index.js: (Prayer times - Code)
Code:
calculatePrayerTime() {
var _this = this;
var prayerSettings = this.defaultPrayerSetting;
console.log(TAG + 'prayer_setting: getPrayerSetting() ' + JSON.stringify(prayerSettings));
if (prayerSettings !== null) {
this.prayerSettings = prayerSettings;
var params = this.getPrayerParameter(this.prayerSettings);
var coordinates = new adhan.Coordinates(_this.locationCoordinates.latitude, _this.locationCoordinates.longitude);
var date = this.date;
var prayerTimes = new adhan.PrayerTimes(coordinates, date, params);
console.info(TAG + 'locationCoordinates ' + JSON.stringify(_this.locationCoordinates));
var timezone = tzlookup(_this.locationCoordinates.latitude, _this.locationCoordinates.longitude)
if(this.config.isTesting === true){
timezone = this.config.timeZone
}
console.log(TAG + "timezone: " + timezone);
var nextPrayer = prayerTimes.nextPrayer(date);
var currentPrayer = prayerTimes.currentPrayer(date);
console.info(TAG + 'nextPrayer ' + nextPrayer);
console.info(TAG + 'currentPrayer ' + currentPrayer);
if (nextPrayer.toString() === "none") {
_this.isShowTargetTime = false
_this.nextPrayer = "Night";
_this.managePrayerTime(prayerTimes, timezone, nextPrayer, currentPrayer)
} else {
_this.isShowTargetTime = true
_this.nextPrayer = nextPrayer;
var nextPrayerTime = prayerTimes.timeForPrayer(nextPrayer);
_this.nextPrayerTime = moment(nextPrayerTime).tz(timezone).format('h:mm A');
_this.setTimeInfo(nextPrayerTime.getTime());
_this.managePrayerTime(prayerTimes, timezone, nextPrayer, currentPrayer)
}
}
},
managePrayerTime(prayerTimes, timezone, nextPrayer, currentPrayer) {
var _this = this;
var fajrTime = moment(prayerTimes.fajr).tz(timezone).format('h:mm A');
var sunriseTime = moment(prayerTimes.sunrise).tz(timezone).format('h:mm A');
var dhuhrTime = moment(prayerTimes.dhuhr).tz(timezone).format('h:mm A');
var asrTime = moment(prayerTimes.asr).tz(timezone).format('h:mm A');
var maghribTime = moment(prayerTimes.maghrib).tz(timezone).format('h:mm A');
var ishaTime = moment(prayerTimes.isha).tz(timezone).format('h:mm A');
_this.prayer_data.map(item => {
if (item.item_id === "fajr") {
item.item_description = fajrTime;
}
if (item.item_id === "dhuhr") {
item.item_description = dhuhrTime;
}
if (item.item_id === "asr") {
item.item_description = asrTime;
}
if (item.item_id === "maghrib") {
item.item_description = maghribTime;
}
if (item.item_id === "isha") {
item.item_description = ishaTime;
}
if (nextPrayer.toString().toLowerCase() === item.item_id) {
_this.prayer_bg = item.item_id + "_bg";
_this.dialog_bg = item.item_id + "_color";
}
});
},
getPrayerParameter(prayerSettings) {
var params = adhan.CalculationMethod.UmmAlQura();
var prayerSetting = prayerSettings.prayerSetting;
if (prayerSetting.calculationMethod === 'MuslimWorldLeagueMuslimWorldLeague') {
params = adhan.CalculationMethod.MuslimWorldLeague();
} else if (prayerSetting.calculationMethod === 'Egyptian') {
params = adhan.CalculationMethod.Egyptian();
} else if (prayerSetting.calculationMethod === 'Karachi') {
params = adhan.CalculationMethod.Karachi();
} else if (prayerSetting.calculationMethod === 'Dubai') {
params = adhan.CalculationMethod.Dubai();
} else if (prayerSetting.calculationMethod === 'MoonsightingCommittee') {
params = adhan.CalculationMethod.MoonsightingCommittee();
} else if (prayerSetting.calculationMethod === 'NorthAmerica') {
params = adhan.CalculationMethod.NorthAmerica();
} else if (prayerSetting.calculationMethod === 'Kuwait') {
params = adhan.CalculationMethod.Kuwait();
} else if (prayerSetting.calculationMethod === 'Qatar') {
params = adhan.CalculationMethod.Qatar();
} else if (prayerSetting.calculationMethod === 'Singapore') {
params = adhan.CalculationMethod.Singapore();
} else if (prayerSetting.calculationMethod === 'Other') {
params = adhan.CalculationMethod.Other();
}
if (prayerSetting.Madhab === 'Shafi') {
params.madhab = adhan.Madhab.Shafi;
} else {
params.madhab = adhan.Madhab.Hanafi;
}
params.adjustments.fajr = parseInt(prayerSetting.adjustments.fajr) || 0;
params.adjustments.sunrise = parseInt(prayerSetting.adjustments.sunrise) || 0;
params.adjustments.dhuhr = parseInt(prayerSetting.adjustments.dhuhr) || 0;
params.adjustments.asr = parseInt(prayerSetting.adjustments.asr) || 0;
params.adjustments.maghrib = parseInt(prayerSetting.adjustments.maghrib) || 0;
params.adjustments.isha = parseInt(prayerSetting.adjustments.isha) || 0;
return params;
},
index.js: (Count down timer - Code)
Code:
setTimeInfo(next_time) {
console.log(TAG + "next_time: " + next_time);
this.CaculateTime(next_time);
this.countDownTimer = setInterval(() => {
this.CaculateTime(next_time);
}, 1000);
},
CaculateTime(timeObj) {
var myDate = new Date();
if (this.config.isTesting === true) {
this.date = moment(this.date).add(500, 'milliseconds').toDate();
myDate = this.date;
}
let currentTime = myDate.getTime();
var targetTime = parseInt(timeObj);
var remainTime = parseInt(targetTime - currentTime);
if (remainTime > 0) {
this.isShowTargetTime = true;
this.setRemainTime(remainTime);
//this.setTargetTime(targetTime);
}
},
setRemainTime(remainTime) {
let days = this.addZero(Math.floor(remainTime / (24 * 3600 * 1000))); // Calculate the number of days
let leavel = remainTime % (24 * 3600 * 1000); // Time remaining after counting days
let hours = this.addZero(Math.floor(leavel / (3600 * 1000))); // Calculate the number of hours remaining
let leavel2 = leavel % (3600 * 1000); // Number of milliseconds remaining after calculating the remaining hours
let minutes = this.addZero(Math.floor(leavel2 / (60 * 1000))); // Calculate the number of minutes remaining
// Calculate the difference seconds.
let leavel3 = leavel2 % (60 * 1000); // Number of milliseconds remaining after minutes are calculated
let seconds = this.addZero(Math.round(leavel3 / 1000));
this.nextPrayerRemaining = hours + ':' + minutes + ':' + seconds;
},
setTargetTime(targetTime) {
var _this = this
var times = new Date(targetTime);
let date = times.toLocaleDateString(); //Gets the current date
var tempSetHours = times.getHours(); //Gets the current number of hours (0 - 23)
let hours = this.addZero(tempSetHours)
var tempSetMinutes = times.getMinutes(); //Gets the current number of minutes (0 - 59)
let minutes = this.addZero(tempSetMinutes)
var tempSetSeconds = times.getSeconds(); //Gets the current number of seconds (0 - 59)
let seconds = this.addZero(tempSetSeconds)
this.targetTime = `${hours}:${minutes}:${seconds}`;
},
addZero: function (i) {
return i < 10 ? "0" + i : i + "";
},
Prayer time Screen Notes:
To manage different state of application on single screen, we can able to use logic layouts using if=”true/false” or show=”true/false” conditions on containers.
For testing of custom date and time developer need to modify config data variable (isTesting: true).
For production we need to apply isTesting: false and relay on real date and time.
For prayer time parameter we implement adhan npm libraries, developer can have access on prayer time adjustment (plus/minus) in minutes.
For better management of prayer time parameters always use local storage (key/value), to save user preferences in storage and adjust prayer time.
5. Result
Tips & Tricks:
HarmonyOS JS project while installing any NPM libraries, in terminal must be on entry folder of your project module.
For testing of any date and time, developer need to modify config data variable (isTesting: true)
For production or realtime device, developer need to modify config data variable (isTesting: false)
For prayer time adjustment developer can modify defaultPrayerSetting data variable and could store user preference in storage.
Requesting some data from internet, you must need to add Internet permission in config.json file.
Fetching Location data, you must need to add Internet Permission in config.json file.
Use Dev Eco Studio Previewer to check the screen layout and design. Previewer is developer friendly to Hot release changes on fly.
For better management of big application it’s a good practice to centralize you common scripts and common style in common folder. Add images folder for complete application images.
In JS script when you make some variable, in callback functions you can store the reference of this to some variable and then call reference variable. Like var _this = this.
References:
HarmonyOS JS API Official Documentation: https://developer.harmonyos.com/en/docs/documentation/doc-references/js-apis-overview-0000001056361791
Geographic Location Documentation: https://developer.harmonyos.com/en/docs/documentation/doc-references/js-apis-system-location-0000000000626089
Conclusion:
Developers can able to develop real world Prayer time calculation application, while fetch user location data and using npm ready-made libraries. While developing application for HarmonyOS developer can get benefit for both JS and JAVA language. Benefit for developing JS based HarmonyOS application developer can able to use npm based libraries and can reduce development time.
Original Source
Useful sharing, thanks!!
Very useful. Thanks for sharing

Categories

Resources