watch_theme_models.dart 7.78 KB
import 'dart:ui';

import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';

import '../widgets/watch_theme_colors.dart';

class WatchThemeItem {
  const WatchThemeItem({
    this.id,
    this.userId,
    this.status,
    required this.themeName,
    required this.energeticDescription,
    this.energeticImage,
    required this.normalDescription,
    this.normalImage,
    required this.slightStressfulDescription,
    this.slightStressfulImage,
    required this.stressfulDescription,
    this.stressfulImage,
    this.isOfficial = 0,
    this.isDefaultTheme = 0,
    this.officialThemeId,
    this.createTime,
    this.updateTime,
  });

  final int? id;
  final int? userId;
  final int? status;
  final String themeName;
  final String energeticDescription;
  final String? energeticImage;
  final String normalDescription;
  final String? normalImage;
  final String slightStressfulDescription;
  final String? slightStressfulImage;
  final String stressfulDescription;
  final String? stressfulImage;
  final int isOfficial;
  final int isDefaultTheme;
  final int? officialThemeId;
  final int? createTime;
  final int? updateTime;

  factory WatchThemeItem.fromJson(Map<String, dynamic> json) {
    return WatchThemeItem(
      id: _intFromJson(json['id']),
      userId: _intFromJson(json['user_id']),
      status: _intFromJson(json['status']),
      themeName: _stringFromJson(
        json['theme_name'],
        l10n.watchThemeCustomTheme,
      ),
      energeticDescription: _stringFromJson(
          json['energetic_description'], l10n.watchThemeExcellent),
      energeticImage: _nullableStringFromJson(json['energetic_image']),
      normalDescription:
          _stringFromJson(json['normal_description'], l10n.watchThemeNormal),
      normalImage: _nullableStringFromJson(json['normal_image']),
      slightStressfulDescription: _stringFromJson(
        json['slight_stressful_description'],
        l10n.watchThemeSlightStressful,
      ),
      slightStressfulImage:
          _nullableStringFromJson(json['slight_stressful_image']),
      stressfulDescription: _stringFromJson(
          json['stressful_description'], l10n.watchThemeStressful),
      stressfulImage: _nullableStringFromJson(json['stressful_image']),
      isOfficial: _intFromJson(json['is_official']) ?? 0,
      isDefaultTheme: _intFromJson(json['is_default_theme']) ?? 0,
      officialThemeId: _intFromJson(json['official_theme_id']),
      createTime: _intFromJson(json['create_time']),
      updateTime: _intFromJson(json['update_time']),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      if (id != null) 'id': id,
      if (userId != null) 'user_id': userId,
      if (status != null) 'status': status,
      'theme_name': themeName,
      'energetic_description': energeticDescription,
      'energetic_image': energeticImage,
      'normal_description': normalDescription,
      'normal_image': normalImage,
      'slight_stressful_description': slightStressfulDescription,
      'slight_stressful_image': slightStressfulImage,
      'stressful_description': stressfulDescription,
      'stressful_image': stressfulImage,
      'is_official': isOfficial,
      'is_default_theme': isDefaultTheme,
      if (officialThemeId != null) 'official_theme_id': officialThemeId,
      if (createTime != null) 'create_time': createTime,
      if (updateTime != null) 'update_time': updateTime,
    };
  }

  String get title => themeName;

  bool get isCustomTheme => isOfficial != 1;

  bool get isOfficialTheme => isOfficial == 1;

  bool get isDefault => isDefaultTheme == 1;

  List<WatchThemeItemInfo> get infoList => [
        WatchThemeItemInfo(
          title: energeticDescription,
          image: energeticImage,
        ),
        WatchThemeItemInfo(
          title: normalDescription,
          image: normalImage,
        ),
        WatchThemeItemInfo(
          title: slightStressfulDescription,
          image: slightStressfulImage,
        ),
        WatchThemeItemInfo(
          title: stressfulDescription,
          image: stressfulImage,
        ),
      ];

  static WatchThemeItem empty() {
    return WatchThemeItem(
      themeName: l10n.watchThemeCustomTheme,
      energeticDescription: l10n.watchThemeExcellent,
      normalDescription: l10n.watchThemeNormal,
      slightStressfulDescription: l10n.watchThemeSlightStressful,
      stressfulDescription: l10n.watchThemeStressful,
    );
  }

  static int? _intFromJson(Object? value) {
    if (value is int) return value;
    if (value is num) return value.toInt();
    if (value is String) return int.tryParse(value);
    if (value is bool) return value ? 1 : 0;
    return null;
  }

  static String _stringFromJson(Object? value, String fallback) {
    final result = _nullableStringFromJson(value);
    return result ?? fallback;
  }

  static String? _nullableStringFromJson(Object? value) {
    if (value == null) return null;
    final result = value.toString().trim();
    return result.isEmpty ? null : result;
  }
}

class WatchThemeItemInfo {
  const WatchThemeItemInfo({
    required this.title,
    this.image,
  });

  final String title;
  final String? image;

  String? get imgUrl => _isNetworkImage ? image : null;

  String? get assetPath => _isNetworkImage ? null : image;

  bool get _isNetworkImage {
    final value = image?.toLowerCase();
    return value?.startsWith('http://') == true ||
        value?.startsWith('https://') == true;
  }
}

class WatchThemeResponse {
  const WatchThemeResponse({this.themes = const []});

  final List<WatchThemeItem> themes;

  factory WatchThemeResponse.fromJson(Map<String, dynamic> json) {
    final rawThemes = json['themes'];
    if (rawThemes is! List) return const WatchThemeResponse();
    return WatchThemeResponse(
      themes: rawThemes
          .whereType<Map>()
          .map((theme) => WatchThemeItem.fromJson(
                Map<String, dynamic>.from(theme),
              ))
          .toList(),
    );
  }
}

class WatchThemeUpsertRequest {
  const WatchThemeUpsertRequest({
    this.themeId,
    required this.themeName,
    required this.energeticDescription,
    required this.energeticImage,
    required this.normalDescription,
    required this.normalImage,
    required this.slightStressfulDescription,
    required this.slightStressfulImage,
    required this.stressfulDescription,
    required this.stressfulImage,
  });

  final int? themeId;
  final String themeName;
  final String energeticDescription;
  final String energeticImage;
  final String normalDescription;
  final String normalImage;
  final String slightStressfulDescription;
  final String slightStressfulImage;
  final String stressfulDescription;
  final String stressfulImage;

  Map<String, dynamic> toJson() {
    return {
      if (themeId != null) 'theme_id': themeId,
      'theme_name': themeName,
      'energetic_description': energeticDescription,
      'energetic_image': energeticImage,
      'normal_description': normalDescription,
      'normal_image': normalImage,
      'slight_stressful_description': slightStressfulDescription,
      'slight_stressful_image': slightStressfulImage,
      'stressful_description': stressfulDescription,
      'stressful_image': stressfulImage,
    };
  }
}

List<WatchThemeTemplateItem> get defaultThemeTemplates => [
      WatchThemeTemplateItem(
        title: l10n.watchThemeExcellent,
        color: WatchThemeColors.excellent,
      ),
      WatchThemeTemplateItem(
        title: l10n.watchThemeNormal,
        color: WatchThemeColors.normal,
      ),
      WatchThemeTemplateItem(
        title: l10n.watchThemeSlightStressful,
        color: WatchThemeColors.stress,
      ),
      WatchThemeTemplateItem(
        title: l10n.watchThemeStressful,
        color: WatchThemeColors.overload,
      ),
    ];

class WatchThemeTemplateItem {
  WatchThemeTemplateItem({required this.title, required this.color});

  final String title;
  final Color color;
}