@Entry
@Component
struct ExpiryDateCalculator {
// State variable for text color, initialized to dark gray
@State private textColor: string = "#2e2e2e";
// State variable for shadow border color, initialized to light gray
@State private shadowColor: string = "#d5d5d5";
// State variable for base padding value, initialized to 30
@State private basePadding: number = 30;
// State variable indicating expiration status, initialized to false
@State private isExpired: boolean = false;
// State variable for production date, initialized as empty string
@State private productionDate: string = "";
// State variable for expiration date, initialized as empty string
@State private expiryDate: string = "";
// State variable for remaining valid days, initialized to 0
@State private remainingDays: number = 0;
// Theme color variable, initialized to orange
@State private themeColor: string | Color = Color.Orange;
// State variable tracking input focus status
@State isInputFocused: boolean = false;
// Watched state variable for input text changes
@State @Watch('inputChanged') private inputText: string = "9";
// Watched state variable for selected date
@State @Watch('inputChanged') private selectedDate: Date = new Date()
// Lifecycle hook before component appears
aboutToAppear(): void {
this.inputChanged()
}
// Method to format date as YYYY-MM-DD
getYearMonthDay(date: Date) {
const year: string = date.getFullYear().toString().padStart(4, '0');
const month: string = (date.getMonth() + 1).toString().padStart(2, '0');
const day: string = date.getDate().toString().padStart(2, '0');
return `${year}年${month}月${day}日`;
}
// Input change handler
inputChanged() {
console.info(`selectedDate:${this.selectedDate}`);
this.productionDate = this.getYearMonthDay(this.selectedDate);
let expiryDate: Date = new Date(this.selectedDate);
expiryDate.setDate(expiryDate.getDate() + Number(this.inputText));
this.expiryDate = this.getYearMonthDay(expiryDate);
this.isExpired = expiryDate.getTime() < new Date().getTime();
const timeDifference = expiryDate.getTime() - new Date().getTime();
this.remainingDays = Math.ceil(timeDifference / (1000 * 60 * 60 * 24));
}
// UI construction
build() {
Column() {
Text('Expiry Date Calculator')
.fontColor(this.textColor)
.fontSize(18)
.width('100%')
.height(50)
.textAlign(TextAlign.Center)
.backgroundColor(Color.White)
.shadow({
radius: 2,
color: this.shadowColor,
offsetX: 0,
offsetY: 5
});
Scroll() {
Column() {
// Statistics Display
Column() {
Row() {
Text() {
Span(`Status: `)
Span(`${this.isExpired ? 'Expired' : 'Valid'}`)
.fontColor(this.isExpired ? "#e74c3c" : "#3ace7d")
}
.fontColor(this.textColor)
.fontSize(16)
.layoutWeight(1);
}
.constraintSize({ minHeight: 45 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
Divider();
Row() {
Text() {
Span(`Days Left: `)
Span(`${this.remainingDays < 0 ? 0 : this.remainingDays} `).fontColor(Color.Orange)
Span(' days')
}
.fontColor(this.textColor)
.fontSize(16)
.layoutWeight(1);
}
.constraintSize({ minHeight: 45 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
Divider();
Row() {
Text() {
Span(`Production Date: `)
Span(`${this.productionDate} `)
}
.fontColor(this.textColor)
.fontSize(16)
.layoutWeight(1);
}
.constraintSize({ minHeight: 45 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
Divider();
Row() {
Text() {
Span(`Expiry Date: `)
Span(`${this.expiryDate} `)
}
.fontColor(this.textColor)
.fontSize(16)
.layoutWeight(1);
}
.constraintSize({ minHeight: 45 })
.justifyContent(FlexAlign.SpaceBetween)
.width('100%');
}
.alignItems(HorizontalAlign.Start)
// ... (remaining UI components with similar translations)
}
}
.scrollBar(BarState.Off)
.clip(false);
}
.height('100%')
.width('100%')
.backgroundColor("#f4f8fb");
}
}
Technical Implementation Details
1. State Management
- @State Decorator: Manages component-level state changes
- @Watch Decorator: Automatically triggers inputChanged() on variable updates
- Reactive UI: Automatic UI refresh on state changes
2. Date Calculation
- getYearMonthDay(): Formats Date object to localized string
-
inputChanged():
- Calculates expiration date
- Determines expiration status
- Computes remaining days
3. UI Features
-
Responsive Layout:
- Adaptive spacing using basePadding
- Percentage-based width/height
-
Visual Feedback:
- Dynamic color changes for expiration status
- Input focus highlighting
- Interactive shadow effects
-
Form Components:
- TextInput with number validation
- Calendar picker integration
- Clear button functionality
4. Styling System
- Theme color management
- Dynamic shadow effects
- Consistent spacing system
- Conditional styling based on state
Key Features
- Real-time calculation updates
- Cross-platform compatibility
- Interactive date selection
- Input validation
- Responsive design
Usage Scenarios
- Food industry quality control
- Pharmaceutical expiration tracking
- Retail inventory management
- Consumer product maintenance
This implementation demonstrates HarmonyOS ArkUI's capabilities in building responsive, data-driven applications with clean state management and modern UI components.