### Initialize and Use File Cache Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Initialize the FileCache, then use 'put' to store data and 'get' to retrieve it. The cache uses MD5 hashing for file identification. Ensure the cache directory is initialized before use. ```dart final fileCache = FileCache(); await fileCache.initialize(); final imageData = Uint8List.fromList([...]); await fileCache.put('media/photo.jpg', imageData); final cachedData = await fileCache.get('media/photo.jpg'); if (cachedData != null) { print('缓存命中,大小: ${cachedData.length} bytes'); } else { print('缓存未命中,需要下载'); } await fileCache.clear(); ``` -------------------------------- ### Flutter Clean and Build Commands Source: https://github.com/imlinhanchao/growth-diary/blob/master/depends/video_player_android-2.8.17/HUAWEI_FIX_README.md These bash commands are used to clean the Flutter project, get dependencies, and build a release APK after modifying project configurations. ```bash cd /Users/iwpz/Documents/GitHub/eCommerceFlutter flutter clean flutter pub get flutter build apk --release ``` -------------------------------- ### Generate and Decode Encrypted QR Code Data Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Use QRService to generate encrypted configuration data for QR codes, decode scanned QR data to import configurations, validate QR data, and get a summary of the QR data. ```dart final qrData = QRService.generateEncryptedQRData(config); final scannedData = 'BASE64_ENCODED_QR_DATA'; final importedConfig = QRService.decodeEncryptedQRData(scannedData); if (importedConfig != null) { print('导入成功: ${importedConfig.babyName}'); print('WebDAV: ${importedConfig.webdavUrl}'); } final isValid = QRService.isValidQRData(scannedData); final summary = QRService.getQRDataSummary(scannedData); ``` -------------------------------- ### WebDAVService Implementation Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Concrete implementation of `CloudStorageService` using the WebDAV protocol. Handles file uploads, downloads, caching, and automatic thumbnail generation. ```APIDOC ## WebDAVService Implementation ### Description Concrete implementation of `CloudStorageService` using the WebDAV protocol. Handles file uploads, downloads, caching, and automatic thumbnail generation. ### Methods - **initialize(AppConfig config)**: Initializes the WebDAV service. - **saveDiaryEntry(DiaryEntry entry)**: Saves a diary entry via WebDAV. - **loadAllEntries()**: Loads all diary entries from WebDAV. - **loadEntriesPage(int offset, int limit)**: Loads a paginated list of diary entries from WebDAV. - **uploadImageWithThumbnails(File file, String fileName)**: Uploads an image to WebDAV and generates thumbnails. - **uploadVideoWithThumbnails(File file, String fileName)**: Uploads a video to WebDAV and generates thumbnails. - **downloadFile(String path)**: Downloads a file from WebDAV. - **fileExists(String path)**: Checks if a file exists on the WebDAV server. - **uploadFile(String path, File file, {Function(double)? onProgress})**: Uploads a file to WebDAV with progress reporting. - **deleteEntry(DiaryEntry entry)**: Deletes a diary entry and its associated files from WebDAV. - **clearCache()**: Clears the local cache for WebDAV files. ### Example Usage ```dart // Initialize WebDAV service final webdavService = WebDAVService(); await webdavService.initialize(config); // Save a diary entry final entry = DiaryEntry(...); await webdavService.saveDiaryEntry(entry); // Load all entries final entries = await webdavService.loadAllEntries(); // Upload image with thumbnails final imagePaths = await webdavService.uploadImageWithThumbnails( File('/path/to/photo.jpg'), 'photo.jpg', ); // Download a file final imageData = await webdavService.downloadFile('media/photo.jpg'); // Upload file with progress await webdavService.uploadFile( 'media/large_video.mp4', File('/path/to/large_video.mp4'), onProgress: (progress) { print('Upload progress: ${(progress * 100).toStringAsFixed(1)}%'); }, ); // Delete an entry await webdavService.deleteEntry(entry); // Clear cache await webdavService.clearCache(); ``` ``` -------------------------------- ### Specify ExoPlayer Version for Downgrade Source: https://github.com/imlinhanchao/growth-diary/blob/master/depends/video_player_android-2.8.17/HUAWEI_FIX_README.md This Gradle snippet shows how to define the ExoPlayer version. Downgrading to a version like 1.4.1 is suggested as an alternative solution if other fixes are ineffective. ```gradle def exoplayer_version = "1.4.1" ``` -------------------------------- ### Build and Run Flutter App Source: https://github.com/imlinhanchao/growth-diary/blob/master/README.md Commands for managing Flutter project dependencies, running the app in development mode, and building release versions for Android and iOS. ```bash flutter pub get ``` ```bash flutter run ``` ```bash flutter build apk ``` ```bash flutter build ios ``` -------------------------------- ### 生成签名密钥 Source: https://github.com/imlinhanchao/growth-diary/blob/master/android/README.md 执行 PowerShell 脚本以生成 PKCS12 格式的密钥库文件。 ```powershell .\generate_keystore.ps1 ``` -------------------------------- ### Create Diary Entry from Media Files Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Use EntryCreationService to create diary entries from a list of media files. Entries are automatically grouped by date. A progress callback can be provided. Optionally, specify a single date for all media. ```dart final mediaFiles = [ MediaFile(srcPath: '/path/to/photo1.jpg', type: MediaType.image, createdAt: DateTime(2024, 6, 15)), MediaFile(srcPath: '/path/to/photo2.jpg', type: MediaType.image, createdAt: DateTime(2024, 6, 15)), MediaFile(srcPath: '/path/to/video.mp4', type: MediaType.video, createdAt: DateTime(2024, 6, 16)), ]; final entries = await entryService.createMediaEntry( mediaFiles, '周末出游记录', config, (uploaded, total) { print('处理进度: $uploaded/$total'); }, ); final singleEntry = await entryService.createMediaEntry( mediaFiles, '特别的一天', config, null, DateTime(2024, 6, 20), ); ``` -------------------------------- ### 实现 WebDAV 服务操作 Source: https://context7.com/imlinhanchao/growth-diary/llms.txt 演示了 WebDAVService 的具体使用,包括数据同步、分页加载、媒体上传及缓存管理。 ```dart // 初始化 WebDAV 服务 final webdavService = WebDAVService(); await webdavService.initialize(config); // 保存日记条目到云端 final entry = DiaryEntry( date: DateTime.now(), title: '今天的记录', description: '宝宝今天学会了说"妈妈"', ageInMonths: 10, ); await webdavService.saveDiaryEntry(entry); // 加载所有日记条目 final entries = await webdavService.loadAllEntries(); for (var e in entries) { print('${e.date}: ${e.title}'); } // 分页加载日记条目 final page1 = await webdavService.loadEntriesPage(0, 10); // 前10条 final page2 = await webdavService.loadEntriesPage(10, 10); // 第11-20条 // 上传图片并自动生成缩略图 final imagePaths = await webdavService.uploadImageWithThumbnails( File('/path/to/photo.jpg'), '20240615_baby_photo.jpg', ); // 返回: "media/20240615_baby_photo.jpg|thumbnails/..._medium.jpg|thumbnails/..._small.jpg" // 上传视频并自动生成缩略图 final videoPaths = await webdavService.uploadVideoWithThumbnails( File('/path/to/video.mp4'), '20240615_baby_video.mp4', ); // 下载媒体文件(带缓存) final imageData = await webdavService.downloadFile('media/20240615_baby_photo.jpg'); if (imageData != null) { // 使用 imageData 显示图片 Image.memory(imageData); } // 检查文件是否存在 final exists = await webdavService.fileExists('media/photo.jpg'); // 带进度回调的文件上传 await webdavService.uploadFile( 'media/large_video.mp4', File('/path/to/large_video.mp4'), onProgress: (progress) { print('上传进度: ${(progress * 100).toStringAsFixed(1)}%'); }, ); // 删除日记条目(包括关联的媒体文件) await webdavService.deleteEntry(entry); // 清除本地缓存 await webdavService.clearCache(); ``` -------------------------------- ### 设置环境变量 Source: https://github.com/imlinhanchao/growth-diary/blob/master/android/README.md 通过命令行设置 Android 密钥库密码环境变量,避免在文件中存储敏感信息。 ```powershell $env:ANDROID_KEYSTORE_PASSWORD = "your_actual_store_password" ``` ```cmd set ANDROID_KEYSTORE_PASSWORD=your_actual_store_password ``` -------------------------------- ### 配置应用设置 Source: https://context7.com/imlinhanchao/growth-diary/llms.txt 用于管理宝宝信息和 WebDAV 连接参数,支持通过 copyWith 方法进行配置更新。 ```dart // 创建应用配置 final config = AppConfig( babyName: '小明', babyBirthDate: DateTime(2023, 6, 1), babyConceptionDate: DateTime(2022, 9, 15), // 可选:孕期记录 webdavUrl: 'https://webdav.example.com/dav', username: 'user@example.com', password: 'your-password', videoCompressionThreshold: 10, // 超过10MB的视频自动压缩 webdavMirrors: ['https://mirror1.example.com/dav'], // 备用镜像 ); // 检查配置是否完整 if (config.isConfigured) { print('配置完整,可以开始使用'); } // 获取宝宝当前年龄标签 final ageLabel = config.getAgeLabel(); // 返回 "小明 (18个月)" // 复制并修改配置 final updatedConfig = config.copyWith( babyName: '小明明', videoCompressionThreshold: 20, ); // 序列化配置 final configJson = config.toJson(); ``` -------------------------------- ### Basic HTML and CSS for Growth Diary Source: https://github.com/imlinhanchao/growth-diary/blob/master/web/index.html Provides fundamental styling for the Growth Diary web application, including layout, sizing, and responsive design considerations for dark mode. ```css html { height: 100% } body { margin: 0; min-height: 100%; background-color: #FFFFFF; background-size: 100% 100%; } .center { margin: 0; position: absolute; top: 50%; left: 50%; -ms-transform: translate(-50%, -50%); transform: translate(-50%, -50%); } .contain { display:block; width:100%; height:100%; object-fit: contain; } .stretch { display:block; width:100%; height:100%; } .cover { display:block; width:100%; height:100%; object-fit: cover; } .bottom { position: absolute; bottom: 0; left: 50%; -ms-transform: translate(-50%, 0); transform: translate(-50%, 0); } .bottomLeft { position: absolute; bottom: 0; left: 0; } .bottomRight { position: absolute; bottom: 0; right: 0; } @media (prefers-color-scheme: dark) { body { background-color: #FFFFFF; } } ``` -------------------------------- ### 构建发布 APK Source: https://github.com/imlinhanchao/growth-diary/blob/master/android/README.md 使用 Flutter CLI 构建 release 版本的 Android 安装包。 ```bash flutter build apk --release ``` -------------------------------- ### Force Global Software Decoding Source: https://github.com/imlinhanchao/growth-diary/blob/master/depends/video_player_android-2.8.17/HUAWEI_FIX_README.md This Java code snippet configures ExoPlayer to use software decoding for all devices, ensuring maximum compatibility at the cost of potentially higher performance and power consumption. ```java // 所有设备都用软解码 builder.setRenderersFactory( new DefaultRenderersFactory(context) .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)); ``` -------------------------------- ### MediaService - Media Sharing and Downloading Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Provides functionality to share media files and save them to local storage. ```dart // 分享图片 final success = await MediaService.shareImage( imagePath: 'media/photo.jpg', imageData: imageBytes, cloudService: webdavService, ); // 分享视频 final videoShared = await MediaService.shareVideo( videoPath: 'media/video.mp4', cloudService: webdavService, ); // 下载图片到本地相册/下载目录 final result = await MediaService.downloadImage( imagePath: 'media/photo.jpg', imageData: imageBytes, cloudService: webdavService, ); if (result.success) { print(result.message); // "图片已保存到下载目录: Growth Diary文件夹" } else { print('保存失败: ${result.message}'); } // 下载视频到本地 final videoResult = await MediaService.downloadVideo( videoPath: 'media/video.mp4', cloudService: webdavService, ); // Android: 保存到 Downloads/Growth Diary/ // iOS: 保存到系统相册 ``` -------------------------------- ### AppConfig Data Model Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Stores application configuration, including baby information, WebDAV connection details, and media handling settings. Supports multiple baby profiles and configuration mirroring. ```APIDOC ## AppConfig Data Model ### Description Stores application configuration, including baby information, WebDAV connection details, and media handling settings. Supports multiple baby profiles and configuration mirroring. ### Fields - **babyName** (string) - The name of the baby. - **babyBirthDate** (DateTime) - The birth date of the baby. - **babyConceptionDate** (DateTime, optional) - The conception date for pregnancy tracking. - **webdavUrl** (string) - The URL for the WebDAV server. - **username** (string) - The username for WebDAV authentication. - **password** (string) - The password for WebDAV authentication. - **videoCompressionThreshold** (int) - The file size threshold (in MB) for automatic video compression. - **webdavMirrors** (List, optional) - A list of alternative WebDAV server URLs. ### Methods - **isConfigured**: Returns true if essential configuration is present. - **getAgeLabel()**: Returns a formatted string of the baby's current age. - **copyWith(**...**)**: Creates a new AppConfig instance with updated fields. - **toJson()**: Serializes the AppConfig object to a JSON string. ### Example Usage ```dart // Create application configuration final config = AppConfig( babyName: '小明', babyBirthDate: DateTime(2023, 6, 1), webdavUrl: 'https://webdav.example.com/dav', username: 'user@example.com', password: 'your-password', videoCompressionThreshold: 10, ); // Check if configuration is complete if (config.isConfigured) { print('Configuration is complete.'); } // Get baby's age label final ageLabel = config.getAgeLabel(); // Copy and update configuration final updatedConfig = config.copyWith(babyName: '小明明'); // Serialize configuration final configJson = config.toJson(); ``` ``` -------------------------------- ### WebDAV Data Storage Structure Source: https://github.com/imlinhanchao/growth-diary/blob/master/README.md Illustrates the directory structure and file organization for storing app data on a WebDAV server, including configuration, journal entries, media, and thumbnails. ```directory growth_diary// ├── config.json # 应用配置 ├── entries/ # 日记条目 │ ├── .json │ ├── .json │ └── ... ├── media/ # 原始媒体文件 │ ├── _photo1.jpg │ ├── _video1.mp4 │ └── ... └── thumbnails/ # 缩略图文件 ├── _photo1_thumb.jpg ├── _video1_thumb.jpg └── ... ``` -------------------------------- ### LocalStorageService - Local Configuration Management Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Manages persistent storage for multi-child configurations using SharedPreferences. ```dart final localStorage = LocalStorageService(); // 保存单个配置 await localStorage.saveConfig(config); // 加载所有配置(多宝宝支持) final allConfigs = await localStorage.loadAllConfigs(); // 返回: Map - 以配置ID为键 // 批量保存所有配置 await localStorage.saveAllConfigs(allConfigs); // 获取/设置当前活跃的宝宝配置ID final currentId = await localStorage.getCurrentConfigId(); await localStorage.setCurrentConfigId('new-config-id'); // 删除指定配置 await localStorage.deleteConfig('config-id-to-delete'); // 通用键值存储 await localStorage.saveString('custom_key', 'custom_value'); final value = await localStorage.getString('custom_key'); await localStorage.remove('custom_key'); ``` -------------------------------- ### Enable Software Decoder Fallback for Huawei Devices Source: https://github.com/imlinhanchao/growth-diary/blob/master/depends/video_player_android-2.8.17/HUAWEI_FIX_README.md This Java code snippet demonstrates how to configure ExoPlayer's RenderersFactory to enable software decoder fallback specifically for Huawei devices. This is part of the fix for MediaCodec compatibility issues. ```java // 华为设备启用软解码器回退 if (isHuaweiDevice()) { builder.setRenderersFactory( new DefaultRenderersFactory(context) .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER) .setEnableDecoderFallback(true)); } ``` -------------------------------- ### FileUtils - Media File Processing Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Handles media selection, metadata extraction, thumbnail generation, and video compression. ```dart // 选择多张图片 final images = await FileUtils.selectImages(allowMultiple: true); for (var img in images) { print('选中图片: ${img.srcPath}'); } // 选择单张图片 final singleImage = await FileUtils.selectImages( source: ImageSource.gallery, allowMultiple: false, ); // 从相机拍照 final photo = await FileUtils.takePhoto(); // 选择多个视频 final videos = await FileUtils.selectVideos(allowMultiple: true); // 从相机录制视频 final recordedVideo = await FileUtils.recordVideo(); // 填充文件创建日期(从EXIF或视频元数据读取) final mediaFile = MediaFile(srcPath: '/path/to/photo.jpg', type: MediaType.image); await FileUtils.fillCreationDate(mediaFile); print('创建日期: ${mediaFile.createdAt}'); // 生成缩略图 await FileUtils.fillThumbnail(mediaFile); // mediaFile.thumbPathSmall - 400px 缩略图 // mediaFile.thumbPathMedium - 768px 缩略图 // 单独生成指定尺寸的缩略图 final thumbnail = await FileUtils.generateThumbnail( '/path/to/photo.jpg', MediaType.image, size: 300, ); // 压缩视频 final compressedVideo = await FileUtils.compressVideo('/path/to/large_video.mp4'); if (compressedVideo != null) { print('压缩后文件: ${compressedVideo.path}'); } // 生成基于文件内容的唯一文件名 final file = File('/path/to/photo.jpg'); final stat = await file.stat(); final uniqueName = FileUtils.generateFileName(file, stat); // 返回: "sha256hash.jpg" ``` -------------------------------- ### CloudStorageService Interface Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Abstract interface defining operations for cloud storage interactions, including configuration management, diary entry handling, and file operations. ```APIDOC ## CloudStorageService Interface ### Description Abstract interface defining operations for cloud storage interactions, including configuration management, diary entry handling, and file operations. `WebDAVService` is a concrete implementation. ### Methods - **initialize(AppConfig config)**: Initializes the service with the provided configuration. - **saveConfig(AppConfig config)**: Saves the application configuration. - **loadConfig()**: Loads the application configuration. - **saveDiaryEntry(DiaryEntry entry)**: Saves a diary entry to the cloud. - **loadAllEntries()**: Loads all diary entries from the cloud. - **loadEntriesPage(int offset, int limit)**: Loads a paginated list of diary entries. - **deleteEntry(DiaryEntry entry)**: Deletes a diary entry from the cloud. - **downloadFile(String path)**: Downloads a file from the cloud. - **fileExists(String path)**: Checks if a file exists on the cloud. - **uploadFile(String path, File file, {Function(double)? onProgress})**: Uploads a file with optional progress callback. - **uploadData(String path, Uint8List data, {Function(double)? onProgress})**: Uploads data with optional progress callback. - **uploadMedia(File file, String fileName)**: Uploads a media file. - **uploadImageWithThumbnails(File file, String fileName)**: Uploads an image and generates thumbnails. - **uploadVideoWithThumbnails(File file, String fileName)**: Uploads a video and generates thumbnails. - **clearCache()**: Clears the local cache. - **saveToTempFile(String path, Uint8List? data)**: Saves data to a temporary file. ### Properties - **isInitialized** (bool): Indicates whether the service has been initialized. ``` -------------------------------- ### Flutter Web Entrypoint Loading Source: https://github.com/imlinhanchao/growth-diary/blob/master/web/index.html JavaScript code to load the Flutter engine entrypoint for web applications. This includes configuring the service worker and initializing the engine upon successful entrypoint load. ```javascript window.addEventListener('load', function(ev) { _flutter.loader.loadEntrypoint({ serviceWorker: { serviceWorkerVersion: serviceWorkerVersion, }, onEntrypointLoaded: function(engineInitializer) { engineInitializer.initializeEngine().then(function(appRunner) { appRunner.runApp(); }); } }); }); ``` -------------------------------- ### 项目文件结构 Source: https://github.com/imlinhanchao/growth-diary/blob/master/android/README.md 展示 Android 签名相关的核心配置文件与脚本路径。 ```text android/ ├── key.properties # 签名配置属性文件 ├── app/ │ ├── build.gradle.kts # Gradle 构建配置 │ └── growth-keystore.p12 # 签名密钥库文件(PKCS12 格式,运行脚本后生成) └── generate_keystore.ps1 # 密钥生成脚本 ``` -------------------------------- ### 定义云存储服务接口 Source: https://context7.com/imlinhanchao/growth-diary/llms.txt 定义了与云存储交互的抽象方法,包括日记管理、文件操作及媒体上传。 ```dart abstract class CloudStorageService { // 初始化服务 Future initialize(AppConfig config); // 配置管理 Future saveConfig(AppConfig config); Future loadConfig(); // 日记条目管理 Future saveDiaryEntry(DiaryEntry entry); Future> loadAllEntries(); Future> loadEntriesPage(int offset, int limit); Future deleteEntry(DiaryEntry entry); // 文件操作 Future downloadFile(String path); Future fileExists(String path); Future uploadFile(String path, File file, {Function(double)? onProgress}); Future uploadData(String path, Uint8List data, {Function(double)? onProgress}); // 媒体上传(带缩略图生成) Future uploadMedia(File file, String fileName); Future uploadImageWithThumbnails(File file, String fileName); Future uploadVideoWithThumbnails(File file, String fileName); // 缓存管理 Future clearCache(); Future saveToTempFile(String path, Uint8List? data); bool get isInitialized; } ``` -------------------------------- ### 管理日记条目模型 Source: https://context7.com/imlinhanchao/growth-diary/llms.txt 展示了如何创建、序列化、反序列化日记条目以及获取年龄标签。需要引入 uuid 包以生成唯一标识。 ```dart import 'package:uuid/uuid.dart'; // 创建新的日记条目 final entry = DiaryEntry( date: DateTime(2024, 6, 15), title: '宝宝第一次走路', description: '今天宝宝终于迈出了人生中的第一步!', imagePaths: ['media/20240615_walk_photo.jpg'], videoPaths: ['media/20240615_walk_video.mp4'], imageThumbnails: ['thumbnails/20240615_walk_photo_small.jpg'], videoThumbnails: ['thumbnails/20240615_walk_video_small.jpg'], ageInMonths: 12, ); // 序列化为JSON(用于WebDAV存储) final jsonData = entry.toJson(); // 输出: { // "id": "uuid-string", // "date": "2024-06-15T00:00:00.000", // "title": "宝宝第一次走路", // "description": "今天宝宝终于迈出了人生中的第一步!", // "imagePaths": ["media/20240615_walk_photo.jpg"], // "videoPaths": ["media/20240615_walk_video.mp4"], // "imageThumbnails": ["thumbnails/20240615_walk_photo_small.jpg"], // "videoThumbnails": ["thumbnails/20240615_walk_video_small.jpg"], // "ageInMonths": 12 // } // 从JSON反序列化 final restoredEntry = DiaryEntry.fromJson(jsonData); // 获取年龄标签(需要配置对象) final ageLabel = entry.getAgeLabel(config); // 返回 "1岁" 或 "12个月零5天" final simplifiedLabel = entry.getSimplifiedAgeLabel(config); // 返回 "1周岁" ``` -------------------------------- ### Create Text Diary Entry Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Use EntryCreationService to create a pure text diary entry with an optional custom date. Ensure the WebDAV service is initialized before use. ```dart final entryService = EntryCreationService(webdavService); final textEntry = await entryService.createDiaryEntry( '今天的发现', '宝宝今天发现了镜子里的自己,一直对着镜子笑', config, customDate: DateTime(2024, 6, 15), ); await webdavService.saveDiaryEntry(textEntry); ``` -------------------------------- ### MediaFile - Data Structure Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Defines the data structure for media files including paths, types, and metadata. ```dart // 媒体文件数据结构 final mediaFile = MediaFile( srcPath: '/path/to/file.jpg', type: MediaType.image, // 或 MediaType.video createdAt: DateTime.now(), ); // 处理完成后包含的属性 // mediaFile.srcPath - 原始文件路径 // mediaFile.thumbPathSmall - 小尺寸缩略图数据 (Uint8List) // mediaFile.thumbPathMedium - 中尺寸缩略图数据 (Uint8List) // mediaFile.uploadPath - 上传后的远程路径 // mediaFile.createdAt - 文件创建时间 // mediaFile.isCompressed - 是否已压缩 // mediaFile.description - 描述文字 ``` -------------------------------- ### Set iOS Download Link Source: https://github.com/imlinhanchao/growth-diary/blob/master/site/index.html This JavaScript code dynamically sets the href attribute for an element with the ID 'ios' to construct an itms-services URL for downloading an iOS manifest. Ensure the 'manifest.plist' file is correctly located at the specified path. ```javascript document.getElementById('ios').href = `itms-services://?action=download-manifest&url=${location.origin}/ios/manifest.plist`; ``` -------------------------------- ### AgeCalculator - Age and Date Calculation Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Calculates age in months, detailed age components, and pregnancy weeks, with support for localized formatting. ```dart // 计算月龄 final birthDate = DateTime(2023, 6, 1); final currentDate = DateTime(2024, 6, 15); final ageInMonths = AgeCalculator.calculateAgeInMonths(birthDate, currentDate); // 返回: 12 // 计算详细年龄(年、月、天) final detailedAge = AgeCalculator.calculateDetailedAge(birthDate, currentDate); // 返回: {'years': 1, 'months': 0, 'days': 14} // 计算两个日期之间的差异 final diff = AgeCalculator.calculateDateDifference(birthDate, currentDate); // 返回: {'years': 1, 'months': 0, 'days': 14} // 计算孕期周数 final conceptionDate = DateTime(2022, 9, 15); final recordDate = DateTime(2023, 3, 1); final weeks = AgeCalculator.calculateWeeksSinceConception(conceptionDate, recordDate); // 返回: 24 // 计算周数差异 final weeksDiff = AgeCalculator.calculateWeeksDifference(conceptionDate, recordDate); // 格式化年龄标签(中文) print(AgeCalculator.formatAgeLabel(0)); // "出生" print(AgeCalculator.formatAgeLabel(3)); // "3月龄" print(AgeCalculator.formatAgeLabel(12)); // "1岁" print(AgeCalculator.formatAgeLabel(15)); // "1岁3月" // 格式化详细年龄标签(包含天数) final detailedLabel = AgeCalculator.formatDetailedAgeLabel(currentDate, config); // 返回: "1岁零14天" 或 "孕24周"(如果在出生前) // 格式化简化年龄标签 final simplifiedLabel = AgeCalculator.formatSimplifiedAgeLabel(currentDate, config); // 返回: "1周岁" 或 "1岁2个月" ``` -------------------------------- ### DiaryEntry Data Model Source: https://context7.com/imlinhanchao/growth-diary/llms.txt Represents a single diary entry, including details like date, title, description, media paths, and age information. Supports serialization to and from JSON for storage. ```APIDOC ## DiaryEntry Data Model ### Description Represents a single diary entry, including details like date, title, description, media paths, and age information. Supports serialization to and from JSON for storage. ### Fields - **id** (string) - Unique identifier for the entry. - **date** (DateTime) - The date the diary entry was created. - **title** (string) - The title of the diary entry. - **description** (string) - A detailed description of the event. - **imagePaths** (List) - Paths to associated image files. - **videoPaths** (List) - Paths to associated video files. - **imageThumbnails** (List) - Paths to thumbnail images. - **videoThumbnails** (List) - Paths to thumbnail videos. - **ageInMonths** (int) - The age of the baby in months when the entry was created. ### Methods - **toJson()**: Serializes the DiaryEntry object to a JSON string. - **fromJson(Map json)**: Creates a DiaryEntry object from a JSON map. - **getAgeLabel(AppConfig config)**: Returns a formatted string representing the baby's age at the time of the entry. - **getSimplifiedAgeLabel(AppConfig config)**: Returns a simplified age label (e.g., '1周岁'). ### Example Usage ```dart // Create a new diary entry final entry = DiaryEntry( date: DateTime(2024, 6, 15), title: '宝宝第一次走路', description: '今天宝宝终于迈出了人生中的第一步!', imagePaths: ['media/20240615_walk_photo.jpg'], videoPaths: ['media/20240615_walk_video.mp4'], imageThumbnails: ['thumbnails/20240615_walk_photo_small.jpg'], videoThumbnails: ['thumbnails/20240615_walk_video_small.jpg'], ageInMonths: 12, ); // Serialize to JSON final jsonData = entry.toJson(); // Deserialize from JSON final restoredEntry = DiaryEntry.fromJson(jsonData); ``` ``` -------------------------------- ### Journal Entry JSON Structure Source: https://github.com/imlinhanchao/growth-diary/blob/master/README.md Defines the JSON schema for individual journal entries, including fields for ID, date, title, description, media paths, thumbnail paths, and age in months. ```json { "id": "唯一标识符", "date": "2024-01-15T10:30:00.000Z", "title": "标题", "description": "详细描述", "imagePaths": ["media/20240115_103000_photo1.jpg"], "videoPaths": ["media/20240115_103000_video1.mp4"], "imageThumbnails": ["thumbnails/20240115_103000_photo1_thumb.jpg"], "videoThumbnails": ["thumbnails/20240115_103000_video1_thumb.jpg"], "ageInMonths": 6 } ``` -------------------------------- ### Add Local Dependency Override in pubspec.yaml Source: https://github.com/imlinhanchao/growth-diary/blob/master/depends/video_player_android-2.8.17/HUAWEI_FIX_README.md This YAML snippet shows how to override the 'video_player_android' dependency in your Flutter project's pubspec.yaml file to use a local path. This is required when applying local fixes. ```yaml dependency_overrides: video_player_android: path: ./video_player_android-2.8.17 ``` -------------------------------- ### Check for Huawei Device Manufacturer Source: https://github.com/imlinhanchao/growth-diary/blob/master/depends/video_player_android-2.8.17/HUAWEI_FIX_README.md This Java method checks if the current device is manufactured by Huawei or Honor. It's used to determine if software decoder fallback is necessary. ```java private static boolean isHuaweiDevice() { String manufacturer = Build.MANUFACTURER.toLowerCase(); String brand = Build.BRAND.toLowerCase(); return manufacturer.contains("huawei") || brand.contains("huawei") || manufacturer.contains("honor") || brand.contains("honor"); } ``` -------------------------------- ### Remove Splash Screen from Web Source: https://github.com/imlinhanchao/growth-diary/blob/master/web/index.html JavaScript function to remove splash screen elements from the web page after loading. It targets elements with IDs 'splash' and 'splash-branding'. ```javascript function removeSplashFromWeb() { document.getElementById("splash")?.remove(); document.getElementById("splash-branding")?.remove(); document.body.style.background = "transparent"; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.