HarmonyOS NEXT Practical: Progress Bar

Objective: To achieve visualization of progress.Knowledge points:
Progress: Progress bar component, used to display the progress of content loading or operation processing.Set progress bar style
Progress has 5 optional types, and you can set the progress bar style through ProgressType. ProgressTyp...

? https://www.roastdev.com/post/....harmonyos-next-pract

#news #tech #development

Favicon 
www.roastdev.com

HarmonyOS NEXT Practical: Progress Bar

Objective: To achieve visualization of progress.Knowledge points:
Progress: Progress bar component, used to display the progress of content loading or operation processing.Set progress bar style
Progress has 5 optional types, and you can set the progress bar style through ProgressType. ProgressType types include: ProgressType.Linear (linear style) ProgressType.Ring (ring without scale style), ProgressType.ScaleRing (ring with scale style), ProgressType.Eclipse (circular style), and ProgressType Capsule (capsule style).interface
⛶Progress(options: ProgressOptions)Create a progress bar component.ProgressOptionsobject
value: Specify the current progress value. When setting a value less than 0, set it to 0; when setting a value greater than total, set it to total. Default value: 0
total: Specify the total length of the progress. When setting a value less than or equal to 0, set it to 100. Default value: 100
type: Specify the type of progress bar. Default value: ProgressType.LinearProgress attribute
⛶value(value: number) //Set the current progress value. When setting a value less than 0, set it to 0; when setting a value greater than total, set it to total. Illegal values are not valid. Default value: 0
color(value: ResourceColor | LinearGradient) //Set the foreground color of the progress bar.
style(value: ProgressStyleOptions | CapsuleStyleOptions | RingStyleOptions | LinearStyleOptions | ScaleRingStyleOptions | EclipseStyleOptions)//Set the style of the component.
contentModifier(modifier:ContentModifier)//On the progress component, customize the content area method. modifier: Content modifier, developers need to customize the class to implement the ContentModifier interface.
privacySensitive(isPrivacySensitiveMode: Optional)//Set privacy sensitive, reset progress to zero in privacy mode, and text will be masked. Explanation: Setting null is insensitive. Card framework support is required.ProgressConfiguration property
Value: Current progress value. When the set value is less than 0, set it to 0. When the set value is greater than total, set it to total. Default value: 0, value range: [0, total]
Total: The total length of the progress. Value range: [0, +∞]
CommonProgressStyleOptions property
enableSmoothEffect: The switch for smooth progress and dynamic effects. After enabling the smooth motion effect, the progress will gradually change from the current value to the set value. Otherwise, the progress will suddenly change from the current value to the set value. Default value: trueProgressStyleOptions property
StrokeWidth: Set the width of the progress bar (percentage setting is not supported). Default value: 4.0vp
ScaleCount: Set the total degree of the circular progress bar. Default value: 120, value range: [2, min (width, height)/scaleWidth/2/π]. If it is not within the value range, the style will display as a circular progress bar without a scale.
ScaleWidth: Set the thickness of the circular progress bar scale (percentage setting is not supported). When the scale thickness is greater than the width of the progress bar, it is the system default thickness. Default value: 2.0vp
Actual combat:ProgressBarDemoPage
⛶@Entry
@Component
struct ProgressBarDemoPage {
@State isStart: boolean = false
@State value: number = 0
timer: number = 0

build() {
Column({ space: 20 }) {
Text('进度条Demo')

Text(`当前进度:${this.value}%`)

Progress({ value: this.value, total: 100, type: ProgressType.Linear })
.style({ strokeWidth: 10, enableSmoothEffect: true })

Row({ space: 20 }) {
Column({ space: 10 }) {
SymbolGlyph(this.isStart ? $r('sys.symbol.pause') : $r('sys.symbol.play_fill'))
.fontSize(30)
.renderingStrategy(SymbolRenderingStrategy.SINGLE)
.fontColor([Color.Black])
Text(this.isStart ? '暂停' : '开始')
}
.onClick(() = {
this.isStart = !this.isStart
this.updateProgress()
})

Column({ space: 10 }) {
SymbolGlyph($r('sys.symbol.arrow_counterclockwise'))
.fontSize(30)
.renderingStrategy(SymbolRenderingStrategy.SINGLE)
.fontColor([Color.Black])
Text('重置')
}
.onClick(() = {
clearInterval(this.timer); // 关闭定时器
this.value = 0
})
}
}
.height('100%')
.width('100%')
.padding({ top: 10, right: 20, left: 20 })
}

updateProgress() {
if (this.isStart) {
this.timer = setInterval(() = {
this.value = this.value + 1;
if (this.value === 100) {
clearInterval(this.timer); // 关闭定时器
}
}, 100)
} else {
clearInterval(this.timer); // 关闭定时器
}
}
}

Similar Posts

Similar

Web application firewall on Netlify for free

Talented folks built Netlify to reduce development friction. They offer a generous free tier, which is super helpful for the open-source ecosystem. But Netlify needs resources to grow and stay healthy. They offer paid plans and have also hired a special force called sales.Sales operate strategically...

? https://www.roastdev.com/post/....web-application-fire

#news #tech #development

Favicon 
www.roastdev.com

Web application firewall on Netlify for free

Talented folks built Netlify to reduce development friction. They offer a generous free tier, which is super helpful for the open-source ecosystem. But Netlify needs resources to grow and stay healthy. They offer paid plans and have also hired a special force called sales.Sales operate strategically. They target areas rich in special kind of prey called enterprise. Like experienced hunters, they conserve energy and wait at the watering hole called security.The internet is a wild place. And I’ve said it before — please bear with me. I like to explore the mechanics of Newtonian action and reaction in daily life.Openness and freedom create incredible opportunities for growth. And with great value comes opportunistic behavior. I personally see it as a balancing act and enjoy observing the laws of physics in many forms.


Startup perspective
Last year, I moved all my web apps from an AWS self-managed Kubernetes cluster to Netlify. Since then, I’ve saved 800€ on infrastructure bills and eliminated some complexity. In the process, I did something unusual: I tried an upsell product — GDPR-friendly site analytics for $9/month.Privacy-friendly observability is a fair deal for me. It offers insights without compromising on core values. I was surprised and genuinely puzzled by the results.It turned out that Valisa attracted thousands of daily visitors. Most came from Singapore and the US. That was strange because my service focused on European flights. It sparked my curiosity to dig deeper.I inspected the logs and noticed distinct visitor groups: aggressive crawlers, credential harvesters, vulnerability scanners, reasonable crawlers, and legitimate users. Bad bots, good bots, and humans. My initial reaction was to wait and see.


Bad bots
A few weeks in, I received an alert from Netlify. It warned me that more than half of my server functions quota (125k per month) had been used. Frankly, I like the reality in which resources are limited.In my experience, the most annoying are credential harvesters and vulnerability scanners. They fire 20-30 concurrent requests per second for around five minutes. I guess we can call it a baby DDoS.Reckless bots are the mosquitoes of the net. They get particularly active around holidays. 5k requests per day is a common occurrence, and their favorite food is WordPress.
⛶[{
message: "Blocked request ?",
url: "https://valisa.io/.git/config",
ua: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0",
location: "Amsterdam, The Netherlands",
ip: "45.148.10.80"
},
{
message: "Blocked request ?",
url: "https://valisa.io/wp-content/uploads/gravity_forms/g/f/f/b/",
ua: "",
location: "Dublin, Ireland",
ip: "52.169.211.111"
},
{
message: "Blocked request ?",
url: "https://valisa.io//wp-includes/wlwmanifest.xml",
ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36",
location: "Boardman, United States",
ip: "52.34.1.203"
},
{
message: "Blocked request ?",
url: "https://valisa.io/configs.php",
ua: "",
location: "Washington, United States",
ip: "52.146.39.115"
}]These requests invoke server functions. Naturally, I went to check Netlify's offer for security and was disappointed to see a "Contact Sales" button.It was like me coming to the watering hole. I see hunters; they see me. We both shrug because they are after the wild beast. And nothing happens; we continue with our daily business.


Build WAF
Savanna rewards creativity. I hope this post will help founders like me build their products with fewer distractions. However, this solution is not for every scale.Netlify edge functions offer great power and flexibility. I am fascinated by how tools multiply human potential. Let's build a layered defense for the Astro website.I started by filtering out traffic targeting WordPress and PHP. Then, I focused on requests without user-agent header and those containing specific keywords like .git or .env. These rules deny access to many unwanted visitors.It took me some time to refine them by observing usage patterns. Eventually, I decided to be unwelcoming to bots that don't respect robots.txt, for example, Bytedance. Later, I blocked common automation tools for data scraping by their default user-agent.The hard part is adjusting rules for the specific use case. I remind myself that simplicity prevents bugs. But with granular control, shooting yourself in the leg is easier than ever. Security is in constant conflict with usability. Therefore, it's essential to test changes.


netlify/edge-functions/firewall.ts
⛶import type { Config, Context } from "@netlify/edge-functions"

export default async (request: Request, context: Context) = {
const bannedBotsRegex =
/Bytespider|ByteDance|PetalBot|Scrapy|Go-http-client|python-requests|python-httpx|axios\//i

const userAgent = request.headers.get("user-agent") || ""
const referer = request.headers.get("referer") || ""
const country = context.geo?.country?.name
const countryCode = context.geo?.country?.code
const city = context.geo?.city
const location = [city, country].filter(Boolean).join(", ")
const ip = context.ip
const url = new URL(request.url)
const pathname = url.pathname?.toLowerCase()

// Catch good part of total junk
const badBot = bannedBotsRegex.test(userAgent)
const blankUserAgent = userAgent.length === 0

// Be careful not to block file extensions you actually use
const bannedExtensions = [
".php", // most popular among scanners
".config",
".cgi",
".bak",
".asp",
".aspx",
".jsp",
".py",
".rb",
]

// Any match in url, review before deploy
const bannedKeywords = [
".env",
".git",
".vscode",
".aws",
".ssh",
"/wordpress",
"/wp-admin",
"/wp-content",
"/wp-includes",
]

// Exact url pathnames
const bannedPathnames = ["/admin", "/backup", "/wp"]

// Cool Hazker detection algorithm
const coolHazker = bannedExtensions.some((ext) = pathname?.endsWith(ext)) ||
bannedKeywords.some((keyword) = pathname?.includes(keyword)) ||
bannedPathnames.some((path) = pathname === path)

// Countries
const denyStates = []
const bannedState = denyStates.some((state) = state === countryCode)

// Alright, let's do something about it!
if (bannedState || badBot || blankUserAgent || coolHazker) {
console.log({
message: "Blocked request ?",
url: request.url,
referer: referer,
ua: userAgent,
location: location,
ip: ip,
})
return new Response("Access denied", {
status: 403,
headers: {
"Content-Type": "text/plain; charset=utf-8",
},
})
}
}

export const config: Config = {
// Review before deploy
path: ["/*"],
excludedPath: ["/*.css", "/*.js"],
}Source code - https://github.com/softbeehive/waf


Results
Around eighty percent of my visitors were rogue bots. Smoking them out at the edge is an effective approach that helped me reduce server load and keep my usage within pro plan limits.


Pros

✅ Efficient, does the job
✅ Transparent, full control of the logic
✅ Easy to customize
✅ Affordable



Cons

? Redeploy on changes
? Maintenance
? Prone to human errors



Support
If you like this article, give WAF a star on GitHub and consider supporting my knowledge sharing efforts. Thank you!Donate via PayPal
Similar

Logging Options in Amazon EKS: Fluent Bit vs Fluentd




? Introduction
When it comes to logging in Amazon EKS, two of the most popular tools are Fluent Bit and Fluentd. Both are powerful log forwarders that can collect, filter, and route logs from your Kubernetes workloads to various destinations, such as CloudWatch, S3, Elasticsearch, or thi...

? https://www.roastdev.com/post/....logging-options-in-a

#news #tech #development

Favicon 
www.roastdev.com

Logging Options in Amazon EKS: Fluent Bit vs Fluentd

? Introduction
When it comes to logging in Amazon EKS, two of the most popular tools are Fluent Bit and Fluentd. Both are powerful log forwarders that can collect, filter, and route logs from your Kubernetes workloads to various destinations, such as CloudWatch, S3, Elasticsearch, or third-party observability platforms.This guide provides a visual comparison of Fluent Bit vs Fluentd and offers best practices for using them in your EKS cluster.


? Fluent Bit vs Fluentd: Key Differences



Feature
Fluent Bit
Fluentd




Resource Usage
Lightweight, ideal for edge/devices
Heavier, more flexible


Performance
High throughput, low memory
Lower throughput, higher memory


Plugin Ecosystem
Smaller but growing
Large and mature


Configuration
Simpler
More powerful


CloudWatch Support
Official AWS EKS add-on
Manual setup required


Container Image Size
~5MB
~40MB+





? Choosing the Right Tool



Use Fluent Bit if...
Use Fluentd if...




✅ You're using Fargate

✅ You're on EC2-based nodes and need flexibility


✅ You want lightweight and fast logging
✅ You need advanced filtering or routing



✅ You prefer AWS-managed add-ons

✅ You're already using Fluentd elsewhere in your stack





? Deployment Models



Fluent Bit (EKS Add-on or Helm)
Fluent Bit can be deployed via the official AWS EKS add-on for minimal setup or manually using a Helm chart for more control over configuration.


Fluentd (DaemonSet Deployment)
Fluentd is typically deployed as a DaemonSet using a generic Kubernetes manifest. You’ll need to select a suitable image and provide your own configuration files to define input sources and output destinations.


✅ Best Practices

? Use structured logging (e.g., JSON)
? Assign least-privilege IAM roles to logging agents
? Keep logging agents separate from app containers
? Filter noisy logs to reduce CloudWatch costs
? Route logs based on namespace or label



? Summary
Both Fluent Bit and Fluentd are great options for EKS logging, depending on your needs:

Fluent Bit is fast, lightweight, and works seamlessly with AWS-native solutions — ideal for most users.

Fluentd is a full-featured logging router with deep plugin support — great for advanced pipelines.
Choose the tool that fits your workload, and don’t hesitate to mix both in multi-node-type environments.Happy logging! ?
Similar

HarmonyOS NEXT Practical: Image Magnification and Reduction

Goal: Use two fingers to pinch and zoom in and out of the imageKnowledge points:
PinchGesture is used to trigger a pinch gesture, with a minimum of 2 fingers and a maximum of 5 fingers, and a minimum recognition distance of 5vp.
interface
⛶PinchGesture(value?:{fingers?:number, distance?:number})Th...

? https://www.roastdev.com/post/....harmonyos-next-pract

#news #tech #development

Favicon 
www.roastdev.com

HarmonyOS NEXT Practical: Image Magnification and Reduction

Goal: Use two fingers to pinch and zoom in and out of the imageKnowledge points:
PinchGesture is used to trigger a pinch gesture, with a minimum of 2 fingers and a maximum of 5 fingers, and a minimum recognition distance of 5vp.
interface
⛶PinchGesture(value?:{fingers?:number, distance?:number})The pinch gesture is used to trigger the pinch gesture event and has two optional parameters:
Fingers: Used to declare the minimum number of fingers required to trigger a pinch gesture, with a minimum value of 2, a maximum value of 5, and a default value of 2. The trigger gesture can have more fingers than the number of fingers, but only the fingers that fall first and have the same number as the fingers participate in the gesture calculation.
Distance: Used to declare the minimum distance that triggers the pinch gesture, in vp, with a default value of 5. Explanation: Value range: [0,+∞). When the recognition distance value is less than or equal to 0, it will be converted to the default value.
API15 adds:
isFingerCountLimited
Check the number of fingers touching the screen. If the number of fingers touching the screen is not equal to the minimum number of fingers set to trigger pinching (i.e. the fingers parameter mentioned above), the gesture will not be recognized. The gesture can only be successfully recognized when the hand index of touching the screen is equal to the minimum number of fingers set to trigger the pinch gesture, and the sliding distance meets the threshold requirement (only the two fingers that fall first participate in the gesture calculation, if one of them is lifted, the gesture recognition fails). For gestures that have been successfully recognized, changing the number of fingers touching the screen in the future will not trigger the onActionUpdate event, but it can trigger the onActionEnd event. Default value: false。event
⛶onActionStart(event:(event: GestureEvent) = void) //Pinch gesture recognition successfully callback.
onActionUpdate(event:(event: GestureEvent) = void) //Pinch gesture callback during movement.
onActionEnd(event:(event: GestureEvent) = void) //Pinch gesture recognition successful, triggering a callback when the finger is raised.
onActionCancel(event: () = void) //Pinch gesture recognition successful, triggered callback upon receiving touch cancellation event.attribute
tag: Set Pinch gesture flag to distinguish bound gestures when customizing gesture judgment.
allowedTypes: Set the event input source supported by Pinch gesture.Actual combat:ImageEnlargementReductionDemoPage
⛶@Entry
@Component
struct ImageEnlargementReductionDemoPage {
@State scaleValue: number = 1;
@State pinchValue: number = 1;
@State pinchX: number = 0;
@State pinchY: number = 0;

build() {
Stack({ alignContent: Alignment.Top }) {
Image('https://pica.zhimg.com/v2-764199c9470ff436082f35610f1f81f4_1440w.jpg')
.width('100%')
// 在组件上绑定缩放比例,可以通过修改缩放比例来实现组件的缩小或者放大
.scale({ x: this.scaleValue, y: this.scaleValue, z: 1 })
.gesture(
// 在组件上绑定2指触发的捏合手势
PinchGesture({ fingers: 2 })
.onActionStart((event: GestureEvent | undefined) = {
console.info('Pinch start');
})
// 当捏合手势触发时,可以通过回调函数获取缩放比例,从而修改组件的缩放比例
.onActionUpdate((event: GestureEvent | undefined) = {
if (event) {
this.scaleValue = this.pinchValue * event.scale;
this.pinchX = event.pinchCenterX;
this.pinchY = event.pinchCenterY;
}
})
.onActionEnd(() = {
this.pinchValue = this.scaleValue;
console.info('Pinch end');
})
)

Text('图片放大缩小Demo')
.fontColor(Color.Orange)
.fontSize(24)
}
.width('100%')
.height('100%')
}
}