Project Structure Overview
entry/src/main/ets/
|---ui-components
| |---TabNav.ets // Bottom tab navigation panel
| |---SpecSelector.ets // Product specification selection
| |---PromoDialog.ets // Promotional overlay
| |---ProductInfo.ets // Detailed product specs block
| |---PriceTag.ets // Price display component
|---dummy-data
| |---ProductDetailData.ets // Product detail mock data
| |---ProductListData.ets // Product catalog mock data
|---data-models
| |---ProductDetail.ets // Product detail type definitions
| |---ProductItem.ets // Product item type definitions
|---screens
| |---ProductDetail.ets // Product detail screen
| |---Home.ets // Main catalog screen
| |---ShoppingCart.ets // Cart screen
|---cart-feature
| |---CartPanel.ets // Cart content panel
| |---RecommendedList.ets // Recommended product grid
|---helpers
| |---LogHelper.ets // Log utility wrapper
feature/event-bus/src/main/ets/
|---constants
| |---EventKeys.ts // Event ID constants
|---helpers
| |---feature
| | |---EventBusManager.ets // Custom event emitter wrapper
Custom Event Bus Implementation
import emitter from '@ohos.events.emitter';
import { EventKeys } from '../../constants/EventKeys';
import Base from '@ohos.base';
interface EventPayload {
itemId: number;
}
interface EventWrapper {
payload: EventPayload;
}
export class EventBusManager {
private cartItems: EventWrapper[] = [];
// Trigger one-time promotional overlay display
public triggerPromoOverlay(callback: Base.Callback<emitter.EventData>): void {
const promoEventInner: emitter.InnerEvent = {
eventId: EventKeys.PROMO_SHOW_ID
};
const promoEventPayload: emitter.EventData = {
data: {
triggerKey: EventKeys.PROMO_SHOW_ID
}
};
emitter.once(promoEventInner, callback);
emitter.emit(promoEventInner, promoEventPayload);
}
// Trigger one-time promotional overlay close
public triggerPromoClose(callback: Base.Callback<emitter.EventData>): void {
const closeEventPayload: emitter.EventData = {
data: {
triggerKey: EventKeys.PROMO_CLOSE_ID
}
};
emitter.once(EventKeys.PROMO_CLOSE_ID, callback);
emitter.emit(EventKeys.PROMO_CLOSE_ID, closeEventPayload);
}
// Subscribe to persistent cart add events
public subscribeCartAdd(callback: (data: emitter.EventData) => void): void {
const addEventInner: emitter.InnerEvent = {
eventId: EventKeys.CART_ADD_ID
};
emitter.off(EventKeys.CART_ADD_ID);
emitter.on(addEventInner, (eventData: emitter.EventData) => {
callback(eventData);
});
}
// Subscribe to persistent cart remove events
public subscribeCartRemove(callback: (data: emitter.EventData) => void): void {
emitter.off(EventKeys.CART_REMOVE_ID);
emitter.on(EventKeys.CART_REMOVE_ID, (eventData: emitter.EventData) => {
callback(eventData);
});
}
// Publish cart add event
public publishCartAdd(productId: number): void {
const addEventInner: emitter.InnerEvent = {
eventId: EventKeys.CART_ADD_ID
};
const addEventPayload: emitter.EventData = {
data: {
itemId: productId
}
};
emitter.emit(addEventInner, addEventPayload);
}
// Publish cart remove event
public publishCartRemove(listIndex: number): void {
console.info('publishCartRemove index:', JSON.stringify(listIndex));
const removeEventPayload: emitter.EventData = {
data: {
itemId: listIndex
}
};
emitter.emit(EventKeys.CART_REMOVE_ID, removeEventPayload);
}
// Subscribe to persistent purchase count event
public startPurchaseTracking(): void {
emitter.on(EventKeys.PURCHASE_TRACK_ID, () => {});
}
// Retrieve current purchase count via listener count
public fetchPurchaseCount(callback: (count: number) => void): void {
callback(emitter.getListenerCount(EventKeys.PURCHASE_TRACK_ID));
}
// Reset purchase count by unsubscribing all purchase track listeners
public resetPurchaseCount(callback: (count: number) => void): void {
emitter.off(EventKeys.PURCHASE_TRACK_ID);
callback(emitter.getListenerCount(EventKeys.PURCHASE_TRACK_ID));
}
}
Feature Breakdown
- **Promotional Overlay Display: Uses
emitter.once() with a numeric event ID binds a one-time listener for the CustomDialogController trigger, auto-unsubscribing after execution.
- **Promotional Overlay Close: Uses
emitter.once() with a string event ID binds a one-time listener for dismissing the CustomDialogController, auto-unsubscribing after execution.
- **Cart Item Addition: Uses
emitter.on() with a numeric event ID for persistent listening, updating the cart item array whenever an add event is published.
- **Cart Item Removal: Uses
emitter.on() with a string event ID for persistent listening, updating the cart item array whenever a remove event is published.
- **Purchase Count Tracking: Leverages
emitter.getListenerCount() to track active purchase event listeners, displaying the result on the cart screen; resetting unsubscribes all listeners, returning a count of 0.