/// Domain Entity: News Article /// /// Pure business entity representing a news article or blog post. /// This entity is framework-independent and contains only business logic. library; /// News Article Entity /// /// Represents a news article/blog post in the app. /// Used for displaying news, tips, project showcases, and professional content. class NewsArticle { /// Unique article ID final String id; /// Article title final String title; /// Article excerpt/summary final String excerpt; /// Full article content (optional, may load separately) final String? content; /// Featured image URL final String imageUrl; /// Article category final NewsCategory category; /// Publication date final DateTime publishedDate; /// View count final int viewCount; /// Estimated reading time in minutes final int readingTimeMinutes; /// Whether this is a featured article final bool isFeatured; /// Author name (optional) final String? authorName; /// Author avatar URL (optional) final String? authorAvatar; /// Tags/keywords for the article final List tags; /// Like count final int likeCount; /// Comment count final int commentCount; /// Share count final int shareCount; /// Constructor const NewsArticle({ required this.id, required this.title, required this.excerpt, this.content, required this.imageUrl, required this.category, required this.publishedDate, required this.viewCount, required this.readingTimeMinutes, this.isFeatured = false, this.authorName, this.authorAvatar, this.tags = const [], this.likeCount = 0, this.commentCount = 0, this.shareCount = 0, }); /// Get formatted publication date (dd/MM/yyyy) String get formattedDate { return '${publishedDate.day.toString().padLeft(2, '0')}/' '${publishedDate.month.toString().padLeft(2, '0')}/' '${publishedDate.year}'; } /// Get formatted view count (e.g., "2.3K") String get formattedViewCount { if (viewCount >= 1000) { return '${(viewCount / 1000).toStringAsFixed(1)}K'; } return viewCount.toString(); } /// Get reading time display text String get readingTimeText => '$readingTimeMinutes phút đọc'; /// Copy with method for immutability NewsArticle copyWith({ String? id, String? title, String? excerpt, String? content, String? imageUrl, NewsCategory? category, DateTime? publishedDate, int? viewCount, int? readingTimeMinutes, bool? isFeatured, String? authorName, String? authorAvatar, List? tags, int? likeCount, int? commentCount, int? shareCount, }) { return NewsArticle( id: id ?? this.id, title: title ?? this.title, excerpt: excerpt ?? this.excerpt, content: content ?? this.content, imageUrl: imageUrl ?? this.imageUrl, category: category ?? this.category, publishedDate: publishedDate ?? this.publishedDate, viewCount: viewCount ?? this.viewCount, readingTimeMinutes: readingTimeMinutes ?? this.readingTimeMinutes, isFeatured: isFeatured ?? this.isFeatured, authorName: authorName ?? this.authorName, authorAvatar: authorAvatar ?? this.authorAvatar, tags: tags ?? this.tags, likeCount: likeCount ?? this.likeCount, commentCount: commentCount ?? this.commentCount, shareCount: shareCount ?? this.shareCount, ); } /// Equality operator @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is NewsArticle && other.id == id; } /// Hash code @override int get hashCode { return id.hashCode; } /// String representation @override String toString() { return 'NewsArticle(id: $id, title: $title, category: $category, ' 'publishedDate: $publishedDate, isFeatured: $isFeatured)'; } } /// News Category enum enum NewsCategory { /// General news news, /// Professional/technical content professional, /// Project showcases projects, /// Events events, /// Promotions promotions, } /// Extension for News Category display extension NewsCategoryX on NewsCategory { String get displayName { switch (this) { case NewsCategory.news: return 'Tin tức'; case NewsCategory.professional: return 'Chuyên môn'; case NewsCategory.projects: return 'Dự án'; case NewsCategory.events: return 'Sự kiện'; case NewsCategory.promotions: return 'Khuyến mãi'; } } String get filterName { switch (this) { case NewsCategory.news: return 'news'; case NewsCategory.professional: return 'professional'; case NewsCategory.projects: return 'projects'; case NewsCategory.events: return 'events'; case NewsCategory.promotions: return 'promotions'; } } }