feat(monetization): 수익화 시스템 기반 모델 추가
- MonetizationState freezed 모델 추가 - google_mobile_ads, in_app_purchase 의존성 추가 - IAP 구매 상태, 버프 종료 시점, 복귀 보상 데이터 관리
This commit is contained in:
162
lib/src/core/model/monetization_state.dart
Normal file
162
lib/src/core/model/monetization_state.dart
Normal file
@@ -0,0 +1,162 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import 'package:asciineverdie/src/core/model/game_state.dart';
|
||||
|
||||
part 'monetization_state.freezed.dart';
|
||||
part 'monetization_state.g.dart';
|
||||
|
||||
/// 수익화 시스템 상태
|
||||
///
|
||||
/// IAP 구매 여부, 광고 관련 버프, 복귀 보상 등을 관리
|
||||
@freezed
|
||||
class MonetizationState with _$MonetizationState {
|
||||
const MonetizationState._();
|
||||
|
||||
const factory MonetizationState({
|
||||
/// IAP 광고 제거 구매 여부
|
||||
@Default(false) bool adRemovalPurchased,
|
||||
|
||||
/// 캐릭터 생성 굴리기 남은 횟수 (0-5)
|
||||
@Default(5) int rollsRemaining,
|
||||
|
||||
/// 되돌리기 남은 횟수
|
||||
@Default(1) int undoRemaining,
|
||||
|
||||
/// 되돌리기용 스탯 히스토리 (JSON 변환 커스텀)
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
List<Stats>? rollHistory,
|
||||
|
||||
/// 자동부활 버프 종료 시점 (elapsedMs 기준)
|
||||
int? autoReviveEndMs,
|
||||
|
||||
/// 5배속 버프 종료 시점 (elapsedMs 기준)
|
||||
int? speedBoostEndMs,
|
||||
|
||||
/// 마지막 플레이 시각 (복귀 보상 계산용)
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
DateTime? lastPlayTime,
|
||||
|
||||
/// 미개봉 보물 상자 개수
|
||||
@Default(0) int pendingChests,
|
||||
|
||||
/// 행운의 부적 버프 종료 시점 (elapsedMs 기준)
|
||||
int? luckyCharmEndMs,
|
||||
}) = _MonetizationState;
|
||||
|
||||
factory MonetizationState.fromJson(Map<String, dynamic> json) =>
|
||||
_$MonetizationStateFromJson(json);
|
||||
|
||||
/// 기본 상태 생성 (신규 게임)
|
||||
factory MonetizationState.initial({bool isPaidUser = false}) {
|
||||
return MonetizationState(
|
||||
adRemovalPurchased: isPaidUser,
|
||||
rollsRemaining: 5,
|
||||
undoRemaining: isPaidUser ? 3 : 1,
|
||||
rollHistory: null,
|
||||
pendingChests: 0,
|
||||
);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// 유틸리티 메서드
|
||||
// ===========================================================================
|
||||
|
||||
/// 유료 사용자 여부
|
||||
bool get isPaidUser => adRemovalPurchased;
|
||||
|
||||
/// 무료 사용자 여부
|
||||
bool get isFreeUser => !adRemovalPurchased;
|
||||
|
||||
/// 자동부활 버프 활성 여부 (elapsedMs 기준)
|
||||
bool isAutoReviveActive(int elapsedMs) {
|
||||
if (autoReviveEndMs == null) return false;
|
||||
return elapsedMs < autoReviveEndMs!;
|
||||
}
|
||||
|
||||
/// 5배속 버프 활성 여부 (elapsedMs 기준)
|
||||
/// 유료 사용자는 항상 활성
|
||||
bool isSpeedBoostActive(int elapsedMs) {
|
||||
if (isPaidUser) return true;
|
||||
if (speedBoostEndMs == null) return false;
|
||||
return elapsedMs < speedBoostEndMs!;
|
||||
}
|
||||
|
||||
/// 행운의 부적 버프 활성 여부 (elapsedMs 기준)
|
||||
bool isLuckyCharmActive(int elapsedMs) {
|
||||
if (luckyCharmEndMs == null) return false;
|
||||
return elapsedMs < luckyCharmEndMs!;
|
||||
}
|
||||
|
||||
/// 굴리기 가능 여부
|
||||
bool get canRoll => rollsRemaining > 0;
|
||||
|
||||
/// 되돌리기 가능 여부
|
||||
bool canUndo(int historyLength) {
|
||||
if (undoRemaining <= 0) return false;
|
||||
if (rollHistory == null || rollHistory!.isEmpty) return false;
|
||||
return historyLength > 0;
|
||||
}
|
||||
|
||||
/// 실제 사용 가능한 되돌리기 횟수
|
||||
int availableUndos(int historyLength) {
|
||||
if (rollHistory == null) return 0;
|
||||
final historyAvailable = rollHistory!.length;
|
||||
return undoRemaining < historyAvailable ? undoRemaining : historyAvailable;
|
||||
}
|
||||
|
||||
/// 최대 보물 상자 개수
|
||||
int get maxChests => isPaidUser ? 10 : 5;
|
||||
|
||||
/// 보물 상자가 가득 찼는지 여부
|
||||
bool get isChestsFull => pendingChests >= maxChests;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// JSON 변환 헬퍼
|
||||
// =============================================================================
|
||||
|
||||
/// Stats 리스트 → JSON
|
||||
List<Map<String, dynamic>>? _statsListToJson(List<Stats>? stats) {
|
||||
if (stats == null) return null;
|
||||
return stats
|
||||
.map((s) => {
|
||||
'str': s.str,
|
||||
'con': s.con,
|
||||
'dex': s.dex,
|
||||
'int': s.intelligence,
|
||||
'wis': s.wis,
|
||||
'cha': s.cha,
|
||||
'hpMax': s.hpMax,
|
||||
'mpMax': s.mpMax,
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// JSON → Stats 리스트
|
||||
List<Stats>? _statsListFromJson(List<dynamic>? json) {
|
||||
if (json == null) return null;
|
||||
return json.map((e) {
|
||||
final m = e as Map<String, dynamic>;
|
||||
return Stats(
|
||||
str: m['str'] as int? ?? 0,
|
||||
con: m['con'] as int? ?? 0,
|
||||
dex: m['dex'] as int? ?? 0,
|
||||
intelligence: m['int'] as int? ?? 0,
|
||||
wis: m['wis'] as int? ?? 0,
|
||||
cha: m['cha'] as int? ?? 0,
|
||||
hpMax: m['hpMax'] as int? ?? 0,
|
||||
mpMax: m['mpMax'] as int? ?? 0,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/// DateTime → JSON (밀리초 타임스탬프)
|
||||
int? _dateTimeToJson(DateTime? dateTime) {
|
||||
return dateTime?.millisecondsSinceEpoch;
|
||||
}
|
||||
|
||||
/// JSON → DateTime
|
||||
DateTime? _dateTimeFromJson(int? timestamp) {
|
||||
if (timestamp == null) return null;
|
||||
return DateTime.fromMillisecondsSinceEpoch(timestamp);
|
||||
}
|
||||
444
lib/src/core/model/monetization_state.freezed.dart
Normal file
444
lib/src/core/model/monetization_state.freezed.dart
Normal file
@@ -0,0 +1,444 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'monetization_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
MonetizationState _$MonetizationStateFromJson(Map<String, dynamic> json) {
|
||||
return _MonetizationState.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$MonetizationState {
|
||||
/// IAP 광고 제거 구매 여부
|
||||
bool get adRemovalPurchased => throw _privateConstructorUsedError;
|
||||
|
||||
/// 캐릭터 생성 굴리기 남은 횟수 (0-5)
|
||||
int get rollsRemaining => throw _privateConstructorUsedError;
|
||||
|
||||
/// 되돌리기 남은 횟수
|
||||
int get undoRemaining => throw _privateConstructorUsedError;
|
||||
|
||||
/// 되돌리기용 스탯 히스토리 (JSON 변환 커스텀)
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
List<Stats>? get rollHistory => throw _privateConstructorUsedError;
|
||||
|
||||
/// 자동부활 버프 종료 시점 (elapsedMs 기준)
|
||||
int? get autoReviveEndMs => throw _privateConstructorUsedError;
|
||||
|
||||
/// 5배속 버프 종료 시점 (elapsedMs 기준)
|
||||
int? get speedBoostEndMs => throw _privateConstructorUsedError;
|
||||
|
||||
/// 마지막 플레이 시각 (복귀 보상 계산용)
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
DateTime? get lastPlayTime => throw _privateConstructorUsedError;
|
||||
|
||||
/// 미개봉 보물 상자 개수
|
||||
int get pendingChests => throw _privateConstructorUsedError;
|
||||
|
||||
/// 행운의 부적 버프 종료 시점 (elapsedMs 기준)
|
||||
int? get luckyCharmEndMs => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this MonetizationState to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of MonetizationState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$MonetizationStateCopyWith<MonetizationState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $MonetizationStateCopyWith<$Res> {
|
||||
factory $MonetizationStateCopyWith(
|
||||
MonetizationState value,
|
||||
$Res Function(MonetizationState) then,
|
||||
) = _$MonetizationStateCopyWithImpl<$Res, MonetizationState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool adRemovalPurchased,
|
||||
int rollsRemaining,
|
||||
int undoRemaining,
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
List<Stats>? rollHistory,
|
||||
int? autoReviveEndMs,
|
||||
int? speedBoostEndMs,
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
DateTime? lastPlayTime,
|
||||
int pendingChests,
|
||||
int? luckyCharmEndMs,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$MonetizationStateCopyWithImpl<$Res, $Val extends MonetizationState>
|
||||
implements $MonetizationStateCopyWith<$Res> {
|
||||
_$MonetizationStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of MonetizationState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? adRemovalPurchased = null,
|
||||
Object? rollsRemaining = null,
|
||||
Object? undoRemaining = null,
|
||||
Object? rollHistory = freezed,
|
||||
Object? autoReviveEndMs = freezed,
|
||||
Object? speedBoostEndMs = freezed,
|
||||
Object? lastPlayTime = freezed,
|
||||
Object? pendingChests = null,
|
||||
Object? luckyCharmEndMs = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
adRemovalPurchased: null == adRemovalPurchased
|
||||
? _value.adRemovalPurchased
|
||||
: adRemovalPurchased // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
rollsRemaining: null == rollsRemaining
|
||||
? _value.rollsRemaining
|
||||
: rollsRemaining // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
undoRemaining: null == undoRemaining
|
||||
? _value.undoRemaining
|
||||
: undoRemaining // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
rollHistory: freezed == rollHistory
|
||||
? _value.rollHistory
|
||||
: rollHistory // ignore: cast_nullable_to_non_nullable
|
||||
as List<Stats>?,
|
||||
autoReviveEndMs: freezed == autoReviveEndMs
|
||||
? _value.autoReviveEndMs
|
||||
: autoReviveEndMs // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
speedBoostEndMs: freezed == speedBoostEndMs
|
||||
? _value.speedBoostEndMs
|
||||
: speedBoostEndMs // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
lastPlayTime: freezed == lastPlayTime
|
||||
? _value.lastPlayTime
|
||||
: lastPlayTime // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
pendingChests: null == pendingChests
|
||||
? _value.pendingChests
|
||||
: pendingChests // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
luckyCharmEndMs: freezed == luckyCharmEndMs
|
||||
? _value.luckyCharmEndMs
|
||||
: luckyCharmEndMs // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$MonetizationStateImplCopyWith<$Res>
|
||||
implements $MonetizationStateCopyWith<$Res> {
|
||||
factory _$$MonetizationStateImplCopyWith(
|
||||
_$MonetizationStateImpl value,
|
||||
$Res Function(_$MonetizationStateImpl) then,
|
||||
) = __$$MonetizationStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
bool adRemovalPurchased,
|
||||
int rollsRemaining,
|
||||
int undoRemaining,
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
List<Stats>? rollHistory,
|
||||
int? autoReviveEndMs,
|
||||
int? speedBoostEndMs,
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
DateTime? lastPlayTime,
|
||||
int pendingChests,
|
||||
int? luckyCharmEndMs,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$MonetizationStateImplCopyWithImpl<$Res>
|
||||
extends _$MonetizationStateCopyWithImpl<$Res, _$MonetizationStateImpl>
|
||||
implements _$$MonetizationStateImplCopyWith<$Res> {
|
||||
__$$MonetizationStateImplCopyWithImpl(
|
||||
_$MonetizationStateImpl _value,
|
||||
$Res Function(_$MonetizationStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of MonetizationState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? adRemovalPurchased = null,
|
||||
Object? rollsRemaining = null,
|
||||
Object? undoRemaining = null,
|
||||
Object? rollHistory = freezed,
|
||||
Object? autoReviveEndMs = freezed,
|
||||
Object? speedBoostEndMs = freezed,
|
||||
Object? lastPlayTime = freezed,
|
||||
Object? pendingChests = null,
|
||||
Object? luckyCharmEndMs = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$MonetizationStateImpl(
|
||||
adRemovalPurchased: null == adRemovalPurchased
|
||||
? _value.adRemovalPurchased
|
||||
: adRemovalPurchased // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
rollsRemaining: null == rollsRemaining
|
||||
? _value.rollsRemaining
|
||||
: rollsRemaining // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
undoRemaining: null == undoRemaining
|
||||
? _value.undoRemaining
|
||||
: undoRemaining // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
rollHistory: freezed == rollHistory
|
||||
? _value._rollHistory
|
||||
: rollHistory // ignore: cast_nullable_to_non_nullable
|
||||
as List<Stats>?,
|
||||
autoReviveEndMs: freezed == autoReviveEndMs
|
||||
? _value.autoReviveEndMs
|
||||
: autoReviveEndMs // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
speedBoostEndMs: freezed == speedBoostEndMs
|
||||
? _value.speedBoostEndMs
|
||||
: speedBoostEndMs // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
lastPlayTime: freezed == lastPlayTime
|
||||
? _value.lastPlayTime
|
||||
: lastPlayTime // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
pendingChests: null == pendingChests
|
||||
? _value.pendingChests
|
||||
: pendingChests // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
luckyCharmEndMs: freezed == luckyCharmEndMs
|
||||
? _value.luckyCharmEndMs
|
||||
: luckyCharmEndMs // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$MonetizationStateImpl extends _MonetizationState {
|
||||
const _$MonetizationStateImpl({
|
||||
this.adRemovalPurchased = false,
|
||||
this.rollsRemaining = 5,
|
||||
this.undoRemaining = 1,
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
final List<Stats>? rollHistory,
|
||||
this.autoReviveEndMs,
|
||||
this.speedBoostEndMs,
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
this.lastPlayTime,
|
||||
this.pendingChests = 0,
|
||||
this.luckyCharmEndMs,
|
||||
}) : _rollHistory = rollHistory,
|
||||
super._();
|
||||
|
||||
factory _$MonetizationStateImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$MonetizationStateImplFromJson(json);
|
||||
|
||||
/// IAP 광고 제거 구매 여부
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool adRemovalPurchased;
|
||||
|
||||
/// 캐릭터 생성 굴리기 남은 횟수 (0-5)
|
||||
@override
|
||||
@JsonKey()
|
||||
final int rollsRemaining;
|
||||
|
||||
/// 되돌리기 남은 횟수
|
||||
@override
|
||||
@JsonKey()
|
||||
final int undoRemaining;
|
||||
|
||||
/// 되돌리기용 스탯 히스토리 (JSON 변환 커스텀)
|
||||
final List<Stats>? _rollHistory;
|
||||
|
||||
/// 되돌리기용 스탯 히스토리 (JSON 변환 커스텀)
|
||||
@override
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
List<Stats>? get rollHistory {
|
||||
final value = _rollHistory;
|
||||
if (value == null) return null;
|
||||
if (_rollHistory is EqualUnmodifiableListView) return _rollHistory;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
/// 자동부활 버프 종료 시점 (elapsedMs 기준)
|
||||
@override
|
||||
final int? autoReviveEndMs;
|
||||
|
||||
/// 5배속 버프 종료 시점 (elapsedMs 기준)
|
||||
@override
|
||||
final int? speedBoostEndMs;
|
||||
|
||||
/// 마지막 플레이 시각 (복귀 보상 계산용)
|
||||
@override
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
final DateTime? lastPlayTime;
|
||||
|
||||
/// 미개봉 보물 상자 개수
|
||||
@override
|
||||
@JsonKey()
|
||||
final int pendingChests;
|
||||
|
||||
/// 행운의 부적 버프 종료 시점 (elapsedMs 기준)
|
||||
@override
|
||||
final int? luckyCharmEndMs;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MonetizationState(adRemovalPurchased: $adRemovalPurchased, rollsRemaining: $rollsRemaining, undoRemaining: $undoRemaining, rollHistory: $rollHistory, autoReviveEndMs: $autoReviveEndMs, speedBoostEndMs: $speedBoostEndMs, lastPlayTime: $lastPlayTime, pendingChests: $pendingChests, luckyCharmEndMs: $luckyCharmEndMs)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$MonetizationStateImpl &&
|
||||
(identical(other.adRemovalPurchased, adRemovalPurchased) ||
|
||||
other.adRemovalPurchased == adRemovalPurchased) &&
|
||||
(identical(other.rollsRemaining, rollsRemaining) ||
|
||||
other.rollsRemaining == rollsRemaining) &&
|
||||
(identical(other.undoRemaining, undoRemaining) ||
|
||||
other.undoRemaining == undoRemaining) &&
|
||||
const DeepCollectionEquality().equals(
|
||||
other._rollHistory,
|
||||
_rollHistory,
|
||||
) &&
|
||||
(identical(other.autoReviveEndMs, autoReviveEndMs) ||
|
||||
other.autoReviveEndMs == autoReviveEndMs) &&
|
||||
(identical(other.speedBoostEndMs, speedBoostEndMs) ||
|
||||
other.speedBoostEndMs == speedBoostEndMs) &&
|
||||
(identical(other.lastPlayTime, lastPlayTime) ||
|
||||
other.lastPlayTime == lastPlayTime) &&
|
||||
(identical(other.pendingChests, pendingChests) ||
|
||||
other.pendingChests == pendingChests) &&
|
||||
(identical(other.luckyCharmEndMs, luckyCharmEndMs) ||
|
||||
other.luckyCharmEndMs == luckyCharmEndMs));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
adRemovalPurchased,
|
||||
rollsRemaining,
|
||||
undoRemaining,
|
||||
const DeepCollectionEquality().hash(_rollHistory),
|
||||
autoReviveEndMs,
|
||||
speedBoostEndMs,
|
||||
lastPlayTime,
|
||||
pendingChests,
|
||||
luckyCharmEndMs,
|
||||
);
|
||||
|
||||
/// Create a copy of MonetizationState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$MonetizationStateImplCopyWith<_$MonetizationStateImpl> get copyWith =>
|
||||
__$$MonetizationStateImplCopyWithImpl<_$MonetizationStateImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$MonetizationStateImplToJson(this);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _MonetizationState extends MonetizationState {
|
||||
const factory _MonetizationState({
|
||||
final bool adRemovalPurchased,
|
||||
final int rollsRemaining,
|
||||
final int undoRemaining,
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
final List<Stats>? rollHistory,
|
||||
final int? autoReviveEndMs,
|
||||
final int? speedBoostEndMs,
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
final DateTime? lastPlayTime,
|
||||
final int pendingChests,
|
||||
final int? luckyCharmEndMs,
|
||||
}) = _$MonetizationStateImpl;
|
||||
const _MonetizationState._() : super._();
|
||||
|
||||
factory _MonetizationState.fromJson(Map<String, dynamic> json) =
|
||||
_$MonetizationStateImpl.fromJson;
|
||||
|
||||
/// IAP 광고 제거 구매 여부
|
||||
@override
|
||||
bool get adRemovalPurchased;
|
||||
|
||||
/// 캐릭터 생성 굴리기 남은 횟수 (0-5)
|
||||
@override
|
||||
int get rollsRemaining;
|
||||
|
||||
/// 되돌리기 남은 횟수
|
||||
@override
|
||||
int get undoRemaining;
|
||||
|
||||
/// 되돌리기용 스탯 히스토리 (JSON 변환 커스텀)
|
||||
@override
|
||||
@JsonKey(fromJson: _statsListFromJson, toJson: _statsListToJson)
|
||||
List<Stats>? get rollHistory;
|
||||
|
||||
/// 자동부활 버프 종료 시점 (elapsedMs 기준)
|
||||
@override
|
||||
int? get autoReviveEndMs;
|
||||
|
||||
/// 5배속 버프 종료 시점 (elapsedMs 기준)
|
||||
@override
|
||||
int? get speedBoostEndMs;
|
||||
|
||||
/// 마지막 플레이 시각 (복귀 보상 계산용)
|
||||
@override
|
||||
@JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson)
|
||||
DateTime? get lastPlayTime;
|
||||
|
||||
/// 미개봉 보물 상자 개수
|
||||
@override
|
||||
int get pendingChests;
|
||||
|
||||
/// 행운의 부적 버프 종료 시점 (elapsedMs 기준)
|
||||
@override
|
||||
int? get luckyCharmEndMs;
|
||||
|
||||
/// Create a copy of MonetizationState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$MonetizationStateImplCopyWith<_$MonetizationStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
35
lib/src/core/model/monetization_state.g.dart
Normal file
35
lib/src/core/model/monetization_state.g.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'monetization_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$MonetizationStateImpl _$$MonetizationStateImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$MonetizationStateImpl(
|
||||
adRemovalPurchased: json['adRemovalPurchased'] as bool? ?? false,
|
||||
rollsRemaining: (json['rollsRemaining'] as num?)?.toInt() ?? 5,
|
||||
undoRemaining: (json['undoRemaining'] as num?)?.toInt() ?? 1,
|
||||
rollHistory: _statsListFromJson(json['rollHistory'] as List?),
|
||||
autoReviveEndMs: (json['autoReviveEndMs'] as num?)?.toInt(),
|
||||
speedBoostEndMs: (json['speedBoostEndMs'] as num?)?.toInt(),
|
||||
lastPlayTime: _dateTimeFromJson((json['lastPlayTime'] as num?)?.toInt()),
|
||||
pendingChests: (json['pendingChests'] as num?)?.toInt() ?? 0,
|
||||
luckyCharmEndMs: (json['luckyCharmEndMs'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$MonetizationStateImplToJson(
|
||||
_$MonetizationStateImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'adRemovalPurchased': instance.adRemovalPurchased,
|
||||
'rollsRemaining': instance.rollsRemaining,
|
||||
'undoRemaining': instance.undoRemaining,
|
||||
'rollHistory': _statsListToJson(instance.rollHistory),
|
||||
'autoReviveEndMs': instance.autoReviveEndMs,
|
||||
'speedBoostEndMs': instance.speedBoostEndMs,
|
||||
'lastPlayTime': _dateTimeToJson(instance.lastPlayTime),
|
||||
'pendingChests': instance.pendingChests,
|
||||
'luckyCharmEndMs': instance.luckyCharmEndMs,
|
||||
};
|
||||
72
pubspec.lock
72
pubspec.lock
@@ -301,6 +301,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
google_mobile_ads:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_mobile_ads
|
||||
sha256: "0d4a3744b5e8ed1b8be6a1b452d309f811688855a497c6113fc4400f922db603"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.3.1"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -341,6 +349,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.2"
|
||||
in_app_purchase:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: in_app_purchase
|
||||
sha256: "5cddd7f463f3bddb1d37a72b95066e840d5822d66291331d7f8f05ce32c24b6c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.3"
|
||||
in_app_purchase_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_android
|
||||
sha256: abb254ae159a5a9d4f867795ecb076864faeba59ce015ab81d4cca380f23df45
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0+8"
|
||||
in_app_purchase_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_platform_interface
|
||||
sha256: "1d353d38251da5b9fea6635c0ebfc6bb17a2d28d0e86ea5e083bf64244f1fb4c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
in_app_purchase_storekit:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: in_app_purchase_storekit
|
||||
sha256: f7cbbd7fb47ab5a4fb736fc3f20ae81a4f6def0af9297b3c525ca727761e2589
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.7"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -834,6 +874,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
webview_flutter:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter
|
||||
sha256: a3da219916aba44947d3a5478b1927876a09781174b5a2b67fa5be0555154bf9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.13.1"
|
||||
webview_flutter_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_android
|
||||
sha256: eeeb3fcd5f0ff9f8446c9f4bbc18a99b809e40297528a3395597d03aafb9f510
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.10.11"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_platform_interface
|
||||
sha256: "63d26ee3aca7256a83ccb576a50272edd7cfc80573a4305caa98985feb493ee0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.14.0"
|
||||
webview_flutter_wkwebview:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_wkwebview
|
||||
sha256: e49f378ed066efb13fc36186bbe0bd2425630d4ea0dbc71a18fdd0e4d8ed8ebc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.23.5"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -41,6 +41,10 @@ dependencies:
|
||||
# Code generation annotations
|
||||
freezed_annotation: ^2.4.1
|
||||
json_annotation: ^4.9.0
|
||||
# AdMob 광고
|
||||
google_mobile_ads: ^5.3.0
|
||||
# IAP (인앱 결제)
|
||||
in_app_purchase: ^3.2.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user