Contents
Preface
Feature Demonstration
-
Core Feature 1: Custom Text Sharing
- Technical Background
- Detailed Implementation Steps
- 1. Importing Required Kits and Dependencies
- 2. Defining Data Type APIs
- 3. Creating Mock Data
- 4. Core Sharing Function Implementation
- 5. UI Interaction Implementation
- 6. Data Processing and Formatting
- 7. Utility Methods Implementation
-
Core Feature 2: Status Calculation Based on Time
- Feature Background
- Core Algorithm Implementation
- Status Styling System
-
Complete Code Implementation
- Extended Use Cases
Conclusion
Preface
Hello everyone, I am Ruocheng. Welcome to the HarmonyOS 5 Practical Development Series. This series aims to provide developers with hands-on technical solutions and ready-to-use code samples to help you quickly master core HarmonyOS app development skills.
In this article, we will take an in-depth look at how to implement custom text sharing in your app, as well as how to calculate and display dynamic statuses based on time in standalone apps. These two features are particularly practical for content-based and utility-type apps, offering a wide range of real-world use cases.
Feature Demonstration

As shown below, the four screenshots illustrate:
- Share Pop-up Interface - The system's native share selector
- Share to Notes - Selecting a target app for sharing
- View in Notes - Display of shared content in the target app
- Time-based Status Evaluation - Dynamic status display calculated from time differences
Core Feature 1: Custom Text Sharing
Technical Background
In HarmonyOS 5, the system provides a powerful ShareKit, enabling apps to share content with other apps. Compared with traditional copy-and-paste operations, the system's sharing feature offers several advantages:
- Enhanced user experience:A native, smooth-sharing interface
- Rich content formats:Supports text, images, files, and more
- Smart target recommendations: Automatically recommends suitable apps for sharing
- Privacy security:Sharing is mediated through the system to safeguard user data
Detailed Implementation Steps
1. Importing Required Kits and Dependencies
import { SolarTerm } from '../Utils/Type'
import { SolarTerms } from '../Utils/SolarTerms'
import promptAction from '@ohos.promptAction'
Import { systemShare } from '@kit.ShareKit'; // System sharing capability
Import { uniformTypeDescriptor as utd } from '@kit.ArkData'; // Unified data type description
Import { common } from '@kit.AbilityKit'; // App context capability
Import { BusinessError } from '@kit.BasicServicesKit'; // Business error handling
Code explanation:
-
@kit.ShareKit:Provides system-level sharing capabilities -
@kit.ArkData:Defines data types to ensure proper sharing of content format -
@kit.AbilityKit:Gets app context, which is required for sharing operations -
@kit.BasicServicesKit:Processes potential errors during sharing
2. Defining Data Type APIs
Create the file Utils/Type.ets:
export interface SolarTerm {
/** Solar term name */
name: string;
/** Solar term date (Gregorian calendar) */
date: string;
/** Solar term status (such as "Passed", "Today", "Upcoming") */
status: string;
/** Lunar date description */
lunar_date: string;
/** Solar term source text */
source_text: string;
/** Local icon path */
local_icon_path: string;
/** Solar term description */
description: string;
}
Design description:
- TypeScript APIs ensure data type safety.
- Each field includes clear comments explaining its purpose.
- Structured design facilitates future expansion and maintenance.
3. Creating Mock Data
Create the file Utils/SolarTerms.ets (partial sample shown below):
import {SolarTerm} from "./Type"
export const SolarTerms: SolarTerm[] = [
{
"name": "Minor Cold",
"date": "2025-01-05",
"status": "Passed",
"lunar_date": "[Gregorian calendar January 5, 6, or 7]",
"source_text": "Winter\nhas passed\nMinor Cold\n2025-01-05\n[Gregorian calendar January 5, 6, or 7]",
"local_icon_path": "iconsSolar/XH.png",
"description": "Minor Cold is the 23rd solar term of the 24 Solar Terms and the fifth in winter..."
},
{
"name": "Great Cold",
"date": "2025-01-20",
"status": "Passed",
"lunar_date": "[Gregorian calendar January 19, 20, or 21]",
"source_text": "Winter\nhas passed\nGreat Cold\n2025-01-20\n[Gregorian calendar January 19, 20, or 21]",
"local_icon_path": "iconsSolar/DH.png",
"description": "Great Cold is the final solar term among the 24 Solar Terms..."
}
// ... More data
]
4. Core Sharing Function Implementation
@State currentSolarTerm: SolarTerm | null = null // The currently selected solar term information
/**
* System sharing function
* @param title Sharing title
* @param content Sharing content
* @param description Sharing description
*/
private async share(title: string, content: string, description: string) {
try {
// Create a sharing data object
let shareData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.TEXT, // Specify the data type as text
content: content, // Main sharing content
title: title, // Sharing title
description: description, // Sharing description
thumbnail: new Uint8Array() // Thumbnail (optional)
});
// Create a sharing controller
let controller: systemShare.ShareController = new systemShare.ShareController(shareData);
// Get the UI context and app context
const uiContext: UIContext = this.getUIContext();
const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
// Display the sharing interface
await controller.show(context, {
selectionMode: systemShare.SelectionMode.SINGLE, // Single selection mode
previewMode: systemShare.SharePreviewMode.DEFAULT, // Default preview mode
});
console.log('Sharing succeeded');
} catch (error: BusinessError) {
console.error('Sharing failed:', error);
promptAction.showToast({
message: 'Sharing failed, please try again',
duration: 2000
});
}
}
Technical highlights:
- Data type specification:Use utd.UniformDataType.TEXT to clearly define the shared content as text type
- Context retrieval:Get necessary contexts through getUIContext() and getHostContext()
- Sharing mode configuration:
-
SelectionMode.SINGLE:Allows users to select only one target app -
SharePreviewMode.DEFAULT:Uses the system's default preview style
-
- Error handling:Capture exceptions with try-catch and provide user-friendly error messages
5. UI Interaction Implementation
Button() {
Text('🔗')
.fontSize(20)
}
.width(44)
.height(44)
.borderRadius(22)
.backgroundColor('#FFFFFF')
.shadow({
radius: 8,
color: '#00000015',
offsetY: 2
})
.onClick(() => {
this.shareSolarTerm() // Call the sharing process function
})
UI design description::
- Use a circular button design to provide better visual aesthetics.
- Add shadow effects to enhance dimensionality.
- Use the Emoji icon to provide a clean and intuitive user experience.
6. Data Processing and Formatting
/**
* Core process function for sharing solar term information
*/
private shareSolarTerm() {
const solarTerm = this.currentSolarTerm!
// Get season information and corresponding emoji
const season = this.getSeason()
const seasonEmoji = this.getSeasonEmoji()
// Process description text to prevent excessive length
const shortDescription = solarTerm.description.length > 100
? solarTerm.description.substring(0, 100) + '...'
: solarTerm.description
// Build the sharing title
const title = `🌟 ${solarTerm.name} ${seasonEmoji}`
// Build the sharing content (format with template strings)
const content = `
📅 Solar term time: ${solarTerm.date}
🗓️ Lunar date: ${solarTerm.lunar_date}
🌸 Season: ${season}
📖 Introduction to solar term:
${shortDescription}
🎯 Characteristics of solar term:
• This is an important node among the 24 Solar Terms.
• It marks a significant moment in the ${season} season.
• It reflects the profound understanding of natural rhythms in Chinese culture.
🏮 National Almanac – Inheriting Chinese culture, exploring solar term wisdom.
#24 Solar Terms #${solarTerm.name} #Chinese culture #Traditional solar term`
const description = `Solar Term Knowledge Sharing`
// Execute sharing
this.share(title, content, description)
// Display a success toast
promptAction.showToast({
message: `Shared ${solarTerm.name} solar term information`,
duration: 2000
})
}
Content formatting tips:
- Structured layout:Enhance readability using emoji and symbols
- Length control:Truncate long description texts to maintain concise content
- Tagging:Add hashtags for social media visibility
- Branding:Include app name or slogan to strengthen brand awareness
7. Utility Methods Implementation
/**
* Get the season based on the solar term name
*/
private getSeason(): string {
const name = this.currentSolarTerm!.name
const springTerms = ['Beginning of Spring', 'Rain Water', 'Awakening of Insects', 'Spring Equinox', 'Clear and Bright', 'Grain Rain']
const summerTerms = ['Beginning of Summer', 'Grain Full', 'Grain in Ear', 'Summer Solstice', 'Minor Heat', 'Major Heat']
const autumnTerms = ['Beginning of Autumn', 'End of Heat', 'White Dew', 'Autumnal Equinox', 'Cold Dew', 'Frost Descent']
const winterTerms = ['Beginning of Winter', 'Minor Snow', 'Major Snow', 'Winter Solstice', 'Minor Cold', 'Great Cold']
if (springTerms.includes(name)) return 'Spring'
if (summerTerms.includes(name)) return 'Summer'
if (autumnTerms.includes(name)) return 'Autumn'
if (winterTerms.includes(name)) return 'Winter'
return 'Unknown'
}
/**
* Get the emoji corresponding to the season
*/
private getSeasonEmoji(): string {
const season = this.getSeason()
switch (season) {
case 'Spring': return '🌸'
case 'Summer': return '☀️'
case 'Autumn': return '🍂'
case 'Winter': return '❄️'
default: return '🌍'
}
}
Core Feature 2: Status Calculation Based on Time
Feature Background
In many use cases, it is necessary to display different statuses based on the relationship between the current time and a target time. For example:
- Event status: Not started, In progress, Ended
- Task status: Pending, Processing, Completed
- Time nodes: Upcoming, Ongoing, Passed
Core Algorithm Implementation

As shown in the original diagram, the date field in the data represents the target time, while the current time serves as the reference.
/**
* Core algorithm for calculating the solar term status
* @param solarTerm Solar term data object
* @returns Status string
*/
private calculateSolarTermStatus(solarTerm: SolarTerm): string {
const today = new Date()
const solarTermDate = new Date(solarTerm.date)
// Reset time to 00:00 to compare only the date portion
// This can avoid the influence of hours, minutes, and seconds on the comparison results.
today.setHours(0, 0, 0, 0)
solarTermDate.setHours(0, 0, 0, 0)
// Calculate the time difference (milliseconds)
const timeDiff = today.getTime() - solarTermDate.getTime()
// Convert to day difference
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
// Return different statuses based on the day difference
if (daysDiff > 0) {
// The target date has passed.
return 'Passed'
} else if (daysDiff === 0) {
// The target date is today.
return 'Today'
} else {
// The target date is in the future.
const daysUntil = Math.abs(daysDiff)
if (daysUntil <= 7) {
// Within one week: display the number of days remaining
return `${daysUntil} days later`
} else if (daysUntil <= 30) {
// Within one month: display the number of weeks remaining
return `${Math.ceil(daysUntil / 7)} weeks later`
} else {
// More than one month away: display "Upcoming"
return 'Upcoming'
}
}
}
Algorithm design highlights::
- Time normalization:Reset time to 00:00 to compare only the date portion
- Millisecond conversion:Use getTime() to get timestamps for precise calculation
- Tiered display:Display days, weeks, or a general status depending on time distance
- User-friendly output:Provide intuitive status descriptions
Status Styling System
To make the status display more intuitive, different color schemes are applied for each status:
/**
* Get text color based on status
*/
private getStatusColor(): string {
const status = this.getCurrentStatus()
if (status === 'Passed') {
return '#E74C3C' // Red: expired
} else if (status === 'Today') {
return '#F39C12' // Orange: in progress
} else if (status.includes('days later') || status.includes('weeks later')) {
return '#3498DB' // Blue: upcoming
} else {
return '#27AE60' // Green: future
}
}
/**
* Get background color based on status
*/
private getStatusBgColor(): string {
const status = this.getCurrentStatus()
if (status === 'Passed') {
return '#FADBD8' // Light red background
} else if (status === 'Today') {
return '#FEF9E7' // Light orange background
} else if (status.includes('days later') || status.includes('weeks later')) {
return '#EBF3FD' // Light blue background
} else {
return '#D5F4E6' // Light green background
}
}
Color design principles:
- Semantic coloring:Each status uses a distinct color tone
- Moderate contrast:Ensure text readability
- Visual hierarchy:Reflect importance through color brightness and saturation
Complete Code Implementation
The following example integrates both core features into a complete implementation:
import { SolarTerm } from '../utils/types'
import { SolarTerms } from '../utils/SolarTerms'
import router from '@ohos.router'
import promptAction from '@ohos.promptAction'
import { systemShare } from '@kit.ShareKit';
import { uniformTypeDescriptor as utd } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct SolarTermsDetail {
@State currentSolarTerm: SolarTerm = {
"name": "Minor Cold",
"date": "2025-01-05",
"status": "Passed",
"lunar_date": "[Gregorian calendar January 5, 6, or 7]",
"source_text": "Winter\nhas passed\nMinor Cold\n2025-01-05\n[Gregorian calendar January 5, 6, or 7]",
"local_icon_path": "iconsSolar/XH.png",
"description": "Minor Cold is the 23rd solar term of the 24 Solar Terms and the fifth in winter. The Big Dipper points to Zi; the solar longitude is 285°; it occurs from January 5–7 in the Gregorian calendar. Minor Cold marks the official beginning of midwinter. Cold accumulates over time, so Minor Cold indicates that the weather is cold but not yet at its extreme. Like Great Cold, Minor Heat, Major Heat, and End of Heat, it is a solar term that reflects temperature changes. The weather characteristics of Minor Cold are: gradually cold, but not extremely cold. As the saying goes, 'the cold is in the three nines,' since the 'three nines' of midwinter generally fall within this solar term, there is a saying, 'Minor Cold is colder than Great Cold.' \nAccording to Chinese meteorological data, Minor Cold is usually the coldest solar term, and only in a few years does Great Cold have lower temperatures than Minor Cold. During Minor Cold, most regions of China enter a severe cold period, with frozen soil and rivers, while cold air continuously moves south from the north, creating harsh weather known as 'The coldest period of winter'. In southern China, although the cold is not as severe as in the north, temperatures drop noticeably. The coldest periods in the south are between Minor Cold and the solar terms Rain Water and Awakening of Insects. Minor Cold is dry and cold, while after Rain Water, the cold becomes wet.
}
/**
* System share feature implementation
*/
private async share(title: string, content: string, description: string) {
try {
let shareData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.TEXT,
content: content,
title: title,
description: description,
thumbnail: new Uint8Array()
});
let controller: systemShare.ShareController = new systemShare.ShareController(shareData);
const uiContext: UIContext = this.getUIContext();
const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
await controller.show(context, {
selectionMode: systemShare.SelectionMode.SINGLE,
previewMode: systemShare.SharePreviewMode.DEFAULT,
});
} catch (error: BusinessError) {
console.error('Sharing failed:', error);
}
}
build() {
Column({ space: 20 }) {
// Share button
Button(`Share ${this.currentSolarTerm? .name} Solar term`)
.width(200)
.height(44)
.backgroundColor('#007AFF')
.borderRadius(22)
.onClick(() => {
this.shareSolarTerm()
})
// Status display
Text(this.calculateSolarTermStatus(this.currentSolarTerm!))
.fontSize(14)
.fontColor(this.getStatusColor())
.backgroundColor(this.getStatusBgColor())
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.borderRadius(12)
}
.width('100%')
.height('100%')
.padding(20)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#E8F4FD', 0.0], ['#F8F9FA', 0.3], ['#FFFFFF', 1.0]]
})
}
// ===== ===== ===== ===== Utility Methods ===== ===== ===== =====
/**
* Get the season of the solar term
*/
private getSeason(): string {
const name = this.currentSolarTerm!.name
const springTerms = ['Beginning of Spring', 'Rain Water', 'Awakening of Insects', 'Spring Equinox', 'Clear and Bright', 'Grain Rain']
const summerTerms = ['Beginning of Summer', 'Grain Full', 'Grain in Ear', 'Summer Solstice', 'Minor Heat', 'Major Heat']
const autumnTerms = ['Beginning of Autumn', 'End of Heat', 'White Dew', 'Autumnal Equinox', 'Cold Dew', 'Frost Descent']
const winterTerms = ['Beginning of Winter', 'Minor Snow', 'Major Snow', 'Winter Solstice', 'Minor Cold', 'Great Cold']
if (springTerms.includes(name)) return 'Spring'
if (summerTerms.includes(name)) return 'Summer'
if (autumnTerms.includes(name)) return 'Autumn'
if (winterTerms.includes(name)) return 'Winter'
return 'Unknown'
}
/**
* Get the emoji corresponding to the season
*/
private getSeasonEmoji(): string {
const season = this.getSeason()
switch (season) {
case 'Spring': return '🌸'
case 'Summer': return '☀️'
case 'Autumn': return '🍂'
case 'Winter': return '❄️'
default: return '🌍'
}
}
/**
* Calculate the solar term status
*/
private calculateSolarTermStatus(solarTerm: SolarTerm): string {
const today = new Date()
const solarTermDate = new Date(solarTerm.date)
// Reset time to 00:00 to compare only the date
today.setHours(0, 0, 0, 0)
solarTermDate.setHours(0, 0, 0, 0)
const timeDiff = today.getTime() - solarTermDate.getTime()
const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
if (daysDiff > 0) {
return 'Passed'
} else if (daysDiff === 0) {
return 'Today'
} else {
const daysUntil = Math.abs(daysDiff)
if (daysUntil <= 7) {
return `${daysUntil} days later`
} else if (daysUntil <= 30) {
return `${Math.ceil(daysUntil / 7)} weeks later`
} else {
return 'Upcoming'
}
}
}
/**
* Get the current calculated status
*/
private getCurrentStatus(): string {
return this.calculateSolarTermStatus(this.currentSolarTerm!)
}
/**
* Get text color based on status
*/
private getStatusColor(): string {
const status = this.getCurrentStatus()
if (status === 'Passed') {
return '#E74C3C'
} else if (status === 'Today') {
return '#F39C12'
} else if (status.includes('days later') || status.includes('weeks later')) {
return '#3498DB'
} else {
return '#27AE60'
}
}
/**
* Get background color based on status
*/
private getStatusBgColor(): string {
const status = this.getCurrentStatus()
if (status === 'Passed') {
return '#FADBD8'
} else if (status === 'Today') {
return '#FEF9E7'
} else if (status.includes('days later') || status.includes('weeks later')) {
return '#EBF3FD'
} else {
return '#D5F4E6'
}
}
/**
* Share solar term information
*/
private shareSolarTerm() {
const solarTerm = this.currentSolarTerm!
const status = this.calculateSolarTermStatus(solarTerm)
const season = this.getSeason()
const seasonEmoji = this.getSeasonEmoji()
// Get a short description (first 100 characters)
const shortDescription = solarTerm.description.length > 100
? solarTerm.description.substring(0, 100) + '...'
: solarTerm.description
const title = `🌟 ${solarTerm.name} ${seasonEmoji}`
const content = `
📅 Solar term time: ${solarTerm.date}
🗓️ Lunar date: ${solarTerm.lunar_date}
⏰ Current status: ${status}
🌸 Season: ${season}
📖 Introduction to solar term:
${shortDescription}
🎯 Characteristics of solar term:
• This is an important node among the 24 Solar Terms.
• It marks a significant moment in the ${season} season.
• It reflects the profound understanding of natural rhythms in Chinese culture.
🏮 National Almanac – Inheriting Chinese culture, exploring solar term wisdom.
#24 Solar Terms #${solarTerm.name} #Chinese culture #Traditional solar term`
const description = `Solar Term Knowledge Sharing`
this.share(title, content, description)
promptAction.showToast({
message: `Shared ${solarTerm.name} solar term information`,
duration: 2000
})
}
}
Extended Use Cases
These two features can be widely applied in the following use cases::
- Content-based apps:article sharing, knowledge dissemination
- Utility-type apps:task management, schedule planning
- Educational apps:study material sharing, progress tracking
- Lifestyle apps:event reminders, status display
Conclusion
This article provides a detailed explanation of the implementation of custom text sharing and time status processing in HarmonyOS 5. By leveraging the system's ShareKit and precise time algorithms, we can offer users an excellent sharing experience and intuitive status display.
These technical solutions are not only applicable to solar term apps but can also be flexibly used in a variety of business use cases. We hope this article helps developers quickly master these practical skills and apply them effectively in real projects.
Top comments (0)