feat: 초기 커밋
- Progress Quest 6.4 Flutter 포팅 프로젝트 - 게임 루프, 상태 관리, UI 구현 - 캐릭터 생성, 인벤토리, 장비, 주문 시스템 - 시장/판매/구매 메커니즘
This commit is contained in:
1
lib/src/core/model/equipment_slot.dart
Normal file
1
lib/src/core/model/equipment_slot.dart
Normal file
@@ -0,0 +1 @@
|
||||
enum EquipmentSlot { weapon, shield, armor }
|
||||
389
lib/src/core/model/game_state.dart
Normal file
389
lib/src/core/model/game_state.dart
Normal file
@@ -0,0 +1,389 @@
|
||||
import 'dart:collection';
|
||||
import 'package:askiineverdie/src/core/util/deterministic_random.dart';
|
||||
|
||||
/// Minimal skeletal state to mirror Progress Quest structures.
|
||||
///
|
||||
/// Logic will be ported faithfully from the Delphi source; this file only
|
||||
/// defines containers and helpers for deterministic RNG.
|
||||
class GameState {
|
||||
GameState({
|
||||
required DeterministicRandom rng,
|
||||
Traits? traits,
|
||||
Stats? stats,
|
||||
Inventory? inventory,
|
||||
Equipment? equipment,
|
||||
SpellBook? spellBook,
|
||||
ProgressState? progress,
|
||||
QueueState? queue,
|
||||
}) : rng = DeterministicRandom.clone(rng),
|
||||
traits = traits ?? Traits.empty(),
|
||||
stats = stats ?? Stats.empty(),
|
||||
inventory = inventory ?? Inventory.empty(),
|
||||
equipment = equipment ?? Equipment.empty(),
|
||||
spellBook = spellBook ?? SpellBook.empty(),
|
||||
progress = progress ?? ProgressState.empty(),
|
||||
queue = queue ?? QueueState.empty();
|
||||
|
||||
factory GameState.withSeed({
|
||||
required int seed,
|
||||
Traits? traits,
|
||||
Stats? stats,
|
||||
Inventory? inventory,
|
||||
Equipment? equipment,
|
||||
SpellBook? spellBook,
|
||||
ProgressState? progress,
|
||||
QueueState? queue,
|
||||
}) {
|
||||
return GameState(
|
||||
rng: DeterministicRandom(seed),
|
||||
traits: traits,
|
||||
stats: stats,
|
||||
inventory: inventory,
|
||||
equipment: equipment,
|
||||
spellBook: spellBook,
|
||||
progress: progress,
|
||||
queue: queue,
|
||||
);
|
||||
}
|
||||
|
||||
final DeterministicRandom rng;
|
||||
final Traits traits;
|
||||
final Stats stats;
|
||||
final Inventory inventory;
|
||||
final Equipment equipment;
|
||||
final SpellBook spellBook;
|
||||
final ProgressState progress;
|
||||
final QueueState queue;
|
||||
|
||||
GameState copyWith({
|
||||
DeterministicRandom? rng,
|
||||
Traits? traits,
|
||||
Stats? stats,
|
||||
Inventory? inventory,
|
||||
Equipment? equipment,
|
||||
SpellBook? spellBook,
|
||||
ProgressState? progress,
|
||||
QueueState? queue,
|
||||
}) {
|
||||
return GameState(
|
||||
rng: rng ?? DeterministicRandom.clone(this.rng),
|
||||
traits: traits ?? this.traits,
|
||||
stats: stats ?? this.stats,
|
||||
inventory: inventory ?? this.inventory,
|
||||
equipment: equipment ?? this.equipment,
|
||||
spellBook: spellBook ?? this.spellBook,
|
||||
progress: progress ?? this.progress,
|
||||
queue: queue ?? this.queue,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 태스크 타입 (원본 fTask.Caption 값들에 대응)
|
||||
enum TaskType {
|
||||
neutral, // heading 등 일반 이동
|
||||
kill, // 몬스터 처치
|
||||
load, // 로딩/초기화
|
||||
plot, // 플롯 진행
|
||||
market, // 시장으로 이동 중
|
||||
sell, // 아이템 판매 중
|
||||
buying, // 장비 구매 중
|
||||
}
|
||||
|
||||
class TaskInfo {
|
||||
const TaskInfo({required this.caption, required this.type});
|
||||
|
||||
final String caption;
|
||||
final TaskType type;
|
||||
|
||||
factory TaskInfo.empty() =>
|
||||
const TaskInfo(caption: '', type: TaskType.neutral);
|
||||
|
||||
TaskInfo copyWith({String? caption, TaskType? type}) {
|
||||
return TaskInfo(caption: caption ?? this.caption, type: type ?? this.type);
|
||||
}
|
||||
}
|
||||
|
||||
class Traits {
|
||||
const Traits({
|
||||
required this.name,
|
||||
required this.race,
|
||||
required this.klass,
|
||||
required this.level,
|
||||
required this.motto,
|
||||
required this.guild,
|
||||
});
|
||||
|
||||
final String name;
|
||||
final String race;
|
||||
final String klass;
|
||||
final int level;
|
||||
final String motto;
|
||||
final String guild;
|
||||
|
||||
factory Traits.empty() => const Traits(
|
||||
name: '',
|
||||
race: '',
|
||||
klass: '',
|
||||
level: 1,
|
||||
motto: '',
|
||||
guild: '',
|
||||
);
|
||||
|
||||
Traits copyWith({
|
||||
String? name,
|
||||
String? race,
|
||||
String? klass,
|
||||
int? level,
|
||||
String? motto,
|
||||
String? guild,
|
||||
}) {
|
||||
return Traits(
|
||||
name: name ?? this.name,
|
||||
race: race ?? this.race,
|
||||
klass: klass ?? this.klass,
|
||||
level: level ?? this.level,
|
||||
motto: motto ?? this.motto,
|
||||
guild: guild ?? this.guild,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Stats {
|
||||
const Stats({
|
||||
required this.str,
|
||||
required this.con,
|
||||
required this.dex,
|
||||
required this.intelligence,
|
||||
required this.wis,
|
||||
required this.cha,
|
||||
required this.hpMax,
|
||||
required this.mpMax,
|
||||
});
|
||||
|
||||
final int str;
|
||||
final int con;
|
||||
final int dex;
|
||||
final int intelligence;
|
||||
final int wis;
|
||||
final int cha;
|
||||
final int hpMax;
|
||||
final int mpMax;
|
||||
|
||||
factory Stats.empty() => const Stats(
|
||||
str: 0,
|
||||
con: 0,
|
||||
dex: 0,
|
||||
intelligence: 0,
|
||||
wis: 0,
|
||||
cha: 0,
|
||||
hpMax: 0,
|
||||
mpMax: 0,
|
||||
);
|
||||
|
||||
Stats copyWith({
|
||||
int? str,
|
||||
int? con,
|
||||
int? dex,
|
||||
int? intelligence,
|
||||
int? wis,
|
||||
int? cha,
|
||||
int? hpMax,
|
||||
int? mpMax,
|
||||
}) {
|
||||
return Stats(
|
||||
str: str ?? this.str,
|
||||
con: con ?? this.con,
|
||||
dex: dex ?? this.dex,
|
||||
intelligence: intelligence ?? this.intelligence,
|
||||
wis: wis ?? this.wis,
|
||||
cha: cha ?? this.cha,
|
||||
hpMax: hpMax ?? this.hpMax,
|
||||
mpMax: mpMax ?? this.mpMax,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InventoryEntry {
|
||||
const InventoryEntry({required this.name, required this.count});
|
||||
|
||||
final String name;
|
||||
final int count;
|
||||
|
||||
InventoryEntry copyWith({String? name, int? count}) {
|
||||
return InventoryEntry(name: name ?? this.name, count: count ?? this.count);
|
||||
}
|
||||
}
|
||||
|
||||
class Inventory {
|
||||
const Inventory({required this.gold, required this.items});
|
||||
|
||||
final int gold;
|
||||
final List<InventoryEntry> items;
|
||||
|
||||
factory Inventory.empty() => const Inventory(gold: 0, items: []);
|
||||
|
||||
Inventory copyWith({int? gold, List<InventoryEntry>? items}) {
|
||||
return Inventory(gold: gold ?? this.gold, items: items ?? this.items);
|
||||
}
|
||||
}
|
||||
|
||||
class Equipment {
|
||||
const Equipment({
|
||||
required this.weapon,
|
||||
required this.shield,
|
||||
required this.armor,
|
||||
required this.bestIndex,
|
||||
});
|
||||
|
||||
final String weapon;
|
||||
final String shield;
|
||||
final String armor;
|
||||
|
||||
/// Tracks best slot index (mirror of Equips.Tag in original code; 0=weapon,1=shield,2=armor).
|
||||
final int bestIndex;
|
||||
|
||||
factory Equipment.empty() => const Equipment(
|
||||
weapon: 'Sharp Stick',
|
||||
shield: '',
|
||||
armor: '',
|
||||
bestIndex: 0,
|
||||
);
|
||||
|
||||
Equipment copyWith({
|
||||
String? weapon,
|
||||
String? shield,
|
||||
String? armor,
|
||||
int? bestIndex,
|
||||
}) {
|
||||
return Equipment(
|
||||
weapon: weapon ?? this.weapon,
|
||||
shield: shield ?? this.shield,
|
||||
armor: armor ?? this.armor,
|
||||
bestIndex: bestIndex ?? this.bestIndex,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SpellEntry {
|
||||
const SpellEntry({required this.name, required this.rank});
|
||||
|
||||
final String name;
|
||||
final String rank; // e.g., Roman numerals
|
||||
|
||||
SpellEntry copyWith({String? name, String? rank}) {
|
||||
return SpellEntry(name: name ?? this.name, rank: rank ?? this.rank);
|
||||
}
|
||||
}
|
||||
|
||||
class SpellBook {
|
||||
const SpellBook({required this.spells});
|
||||
|
||||
final List<SpellEntry> spells;
|
||||
|
||||
factory SpellBook.empty() => const SpellBook(spells: []);
|
||||
|
||||
SpellBook copyWith({List<SpellEntry>? spells}) {
|
||||
return SpellBook(spells: spells ?? this.spells);
|
||||
}
|
||||
}
|
||||
|
||||
class ProgressBarState {
|
||||
const ProgressBarState({required this.position, required this.max});
|
||||
|
||||
final int position;
|
||||
final int max;
|
||||
|
||||
factory ProgressBarState.empty() =>
|
||||
const ProgressBarState(position: 0, max: 1);
|
||||
|
||||
ProgressBarState copyWith({int? position, int? max}) {
|
||||
return ProgressBarState(
|
||||
position: position ?? this.position,
|
||||
max: max ?? this.max,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ProgressState {
|
||||
const ProgressState({
|
||||
required this.task,
|
||||
required this.quest,
|
||||
required this.plot,
|
||||
required this.exp,
|
||||
required this.encumbrance,
|
||||
required this.currentTask,
|
||||
required this.plotStageCount,
|
||||
required this.questCount,
|
||||
});
|
||||
|
||||
final ProgressBarState task;
|
||||
final ProgressBarState quest;
|
||||
final ProgressBarState plot;
|
||||
final ProgressBarState exp;
|
||||
final ProgressBarState encumbrance;
|
||||
final TaskInfo currentTask;
|
||||
final int plotStageCount;
|
||||
final int questCount;
|
||||
|
||||
factory ProgressState.empty() => ProgressState(
|
||||
task: ProgressBarState.empty(),
|
||||
quest: ProgressBarState.empty(),
|
||||
plot: ProgressBarState.empty(),
|
||||
exp: ProgressBarState.empty(),
|
||||
encumbrance: ProgressBarState.empty(),
|
||||
currentTask: TaskInfo.empty(),
|
||||
plotStageCount: 1, // Prologue
|
||||
questCount: 0,
|
||||
);
|
||||
|
||||
ProgressState copyWith({
|
||||
ProgressBarState? task,
|
||||
ProgressBarState? quest,
|
||||
ProgressBarState? plot,
|
||||
ProgressBarState? exp,
|
||||
ProgressBarState? encumbrance,
|
||||
TaskInfo? currentTask,
|
||||
int? plotStageCount,
|
||||
int? questCount,
|
||||
}) {
|
||||
return ProgressState(
|
||||
task: task ?? this.task,
|
||||
quest: quest ?? this.quest,
|
||||
plot: plot ?? this.plot,
|
||||
exp: exp ?? this.exp,
|
||||
encumbrance: encumbrance ?? this.encumbrance,
|
||||
currentTask: currentTask ?? this.currentTask,
|
||||
plotStageCount: plotStageCount ?? this.plotStageCount,
|
||||
questCount: questCount ?? this.questCount,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class QueueEntry {
|
||||
const QueueEntry({
|
||||
required this.kind,
|
||||
required this.durationMillis,
|
||||
required this.caption,
|
||||
this.taskType = TaskType.neutral,
|
||||
});
|
||||
|
||||
final QueueKind kind;
|
||||
final int durationMillis;
|
||||
final String caption;
|
||||
final TaskType taskType;
|
||||
}
|
||||
|
||||
enum QueueKind { task, plot }
|
||||
|
||||
class QueueState {
|
||||
QueueState({Iterable<QueueEntry>? entries})
|
||||
: entries = Queue<QueueEntry>.from(entries ?? const []);
|
||||
|
||||
final Queue<QueueEntry> entries;
|
||||
|
||||
factory QueueState.empty() => QueueState(entries: const []);
|
||||
|
||||
QueueState copyWith({Iterable<QueueEntry>? entries}) {
|
||||
return QueueState(entries: Queue<QueueEntry>.from(entries ?? this.entries));
|
||||
}
|
||||
}
|
||||
31
lib/src/core/model/pq_config.dart
Normal file
31
lib/src/core/model/pq_config.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'package:askiineverdie/data/pq_config_data.dart';
|
||||
|
||||
/// Typed accessors for Progress Quest static data extracted from Config.dfm.
|
||||
class PqConfig {
|
||||
const PqConfig();
|
||||
|
||||
List<String> get spells => _copy('Spells');
|
||||
List<String> get offenseAttrib => _copy('OffenseAttrib');
|
||||
List<String> get defenseAttrib => _copy('DefenseAttrib');
|
||||
List<String> get offenseBad => _copy('OffenseBad');
|
||||
List<String> get defenseBad => _copy('DefenseBad');
|
||||
List<String> get shields => _copy('Shields');
|
||||
List<String> get armors => _copy('Armors');
|
||||
List<String> get weapons => _copy('Weapons');
|
||||
List<String> get specials => _copy('Specials');
|
||||
List<String> get itemAttrib => _copy('ItemAttrib');
|
||||
List<String> get itemOfs => _copy('ItemOfs');
|
||||
List<String> get boringItems => _copy('BoringItems');
|
||||
List<String> get monsters => _copy('Monsters');
|
||||
List<String> get monMods => _copy('MonMods');
|
||||
List<String> get races => _copy('Races');
|
||||
List<String> get klasses => _copy('Klasses');
|
||||
List<String> get titles => _copy('Titles');
|
||||
List<String> get impressiveTitles => _copy('ImpressiveTitles');
|
||||
|
||||
List<String> _copy(String key) {
|
||||
final values = pqConfigData[key];
|
||||
if (values == null) return const [];
|
||||
return List<String>.from(values);
|
||||
}
|
||||
}
|
||||
237
lib/src/core/model/save_data.dart
Normal file
237
lib/src/core/model/save_data.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:askiineverdie/src/core/util/deterministic_random.dart';
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
|
||||
const int kSaveVersion = 2;
|
||||
|
||||
class GameSave {
|
||||
GameSave({
|
||||
required this.version,
|
||||
required this.rngState,
|
||||
required this.traits,
|
||||
required this.stats,
|
||||
required this.inventory,
|
||||
required this.equipment,
|
||||
required this.spellBook,
|
||||
required this.progress,
|
||||
required this.queue,
|
||||
});
|
||||
|
||||
factory GameSave.fromState(GameState state) {
|
||||
return GameSave(
|
||||
version: kSaveVersion,
|
||||
rngState: state.rng.state,
|
||||
traits: state.traits,
|
||||
stats: state.stats,
|
||||
inventory: state.inventory,
|
||||
equipment: state.equipment,
|
||||
spellBook: state.spellBook,
|
||||
progress: state.progress,
|
||||
queue: state.queue,
|
||||
);
|
||||
}
|
||||
|
||||
final int version;
|
||||
final int rngState;
|
||||
final Traits traits;
|
||||
final Stats stats;
|
||||
final Inventory inventory;
|
||||
final Equipment equipment;
|
||||
final SpellBook spellBook;
|
||||
final ProgressState progress;
|
||||
final QueueState queue;
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'version': version,
|
||||
'rng': rngState,
|
||||
'traits': {
|
||||
'name': traits.name,
|
||||
'race': traits.race,
|
||||
'klass': traits.klass,
|
||||
'level': traits.level,
|
||||
'motto': traits.motto,
|
||||
'guild': traits.guild,
|
||||
},
|
||||
'stats': {
|
||||
'str': stats.str,
|
||||
'con': stats.con,
|
||||
'dex': stats.dex,
|
||||
'int': stats.intelligence,
|
||||
'wis': stats.wis,
|
||||
'cha': stats.cha,
|
||||
'hpMax': stats.hpMax,
|
||||
'mpMax': stats.mpMax,
|
||||
},
|
||||
'inventory': {
|
||||
'gold': inventory.gold,
|
||||
'items': inventory.items
|
||||
.map((e) => {'name': e.name, 'count': e.count})
|
||||
.toList(),
|
||||
},
|
||||
'equipment': {
|
||||
'weapon': equipment.weapon,
|
||||
'shield': equipment.shield,
|
||||
'armor': equipment.armor,
|
||||
'bestIndex': equipment.bestIndex,
|
||||
},
|
||||
'spells': spellBook.spells
|
||||
.map((e) => {'name': e.name, 'rank': e.rank})
|
||||
.toList(),
|
||||
'progress': {
|
||||
'task': _barToJson(progress.task),
|
||||
'quest': _barToJson(progress.quest),
|
||||
'plot': _barToJson(progress.plot),
|
||||
'exp': _barToJson(progress.exp),
|
||||
'encumbrance': _barToJson(progress.encumbrance),
|
||||
'taskInfo': {
|
||||
'caption': progress.currentTask.caption,
|
||||
'type': progress.currentTask.type.name,
|
||||
},
|
||||
'plotStages': progress.plotStageCount,
|
||||
'questCount': progress.questCount,
|
||||
},
|
||||
'queue': queue.entries
|
||||
.map(
|
||||
(e) => {
|
||||
'kind': e.kind.name,
|
||||
'duration': e.durationMillis,
|
||||
'caption': e.caption,
|
||||
'taskType': e.taskType.name,
|
||||
},
|
||||
)
|
||||
.toList(),
|
||||
};
|
||||
}
|
||||
|
||||
static GameSave fromJson(Map<String, dynamic> json) {
|
||||
final traitsJson = json['traits'] as Map<String, dynamic>;
|
||||
final statsJson = json['stats'] as Map<String, dynamic>;
|
||||
final inventoryJson = json['inventory'] as Map<String, dynamic>;
|
||||
final equipmentJson = json['equipment'] as Map<String, dynamic>;
|
||||
final progressJson = json['progress'] as Map<String, dynamic>;
|
||||
final queueJson = (json['queue'] as List<dynamic>? ?? []).cast<dynamic>();
|
||||
final spellsJson = (json['spells'] as List<dynamic>? ?? []).cast<dynamic>();
|
||||
|
||||
return GameSave(
|
||||
version: json['version'] as int? ?? kSaveVersion,
|
||||
rngState: json['rng'] as int? ?? 0,
|
||||
traits: Traits(
|
||||
name: traitsJson['name'] as String? ?? '',
|
||||
race: traitsJson['race'] as String? ?? '',
|
||||
klass: traitsJson['klass'] as String? ?? '',
|
||||
level: traitsJson['level'] as int? ?? 1,
|
||||
motto: traitsJson['motto'] as String? ?? '',
|
||||
guild: traitsJson['guild'] as String? ?? '',
|
||||
),
|
||||
stats: Stats(
|
||||
str: statsJson['str'] as int? ?? 0,
|
||||
con: statsJson['con'] as int? ?? 0,
|
||||
dex: statsJson['dex'] as int? ?? 0,
|
||||
intelligence: statsJson['int'] as int? ?? 0,
|
||||
wis: statsJson['wis'] as int? ?? 0,
|
||||
cha: statsJson['cha'] as int? ?? 0,
|
||||
hpMax: statsJson['hpMax'] as int? ?? 0,
|
||||
mpMax: statsJson['mpMax'] as int? ?? 0,
|
||||
),
|
||||
inventory: Inventory(
|
||||
gold: inventoryJson['gold'] as int? ?? 0,
|
||||
items: (inventoryJson['items'] as List<dynamic>? ?? [])
|
||||
.map(
|
||||
(e) => InventoryEntry(
|
||||
name: (e as Map<String, dynamic>)['name'] as String? ?? '',
|
||||
count: (e)['count'] as int? ?? 0,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
equipment: Equipment(
|
||||
weapon: equipmentJson['weapon'] as String? ?? 'Sharp Stick',
|
||||
shield: equipmentJson['shield'] as String? ?? '',
|
||||
armor: equipmentJson['armor'] as String? ?? '',
|
||||
bestIndex: equipmentJson['bestIndex'] as int? ?? 0,
|
||||
),
|
||||
spellBook: SpellBook(
|
||||
spells: spellsJson
|
||||
.map(
|
||||
(e) => SpellEntry(
|
||||
name: (e as Map<String, dynamic>)['name'] as String? ?? '',
|
||||
rank: (e)['rank'] as String? ?? 'I',
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
progress: ProgressState(
|
||||
task: _barFromJson(progressJson['task'] as Map<String, dynamic>? ?? {}),
|
||||
quest: _barFromJson(
|
||||
progressJson['quest'] as Map<String, dynamic>? ?? {},
|
||||
),
|
||||
plot: _barFromJson(progressJson['plot'] as Map<String, dynamic>? ?? {}),
|
||||
exp: _barFromJson(progressJson['exp'] as Map<String, dynamic>? ?? {}),
|
||||
encumbrance: _barFromJson(
|
||||
progressJson['encumbrance'] as Map<String, dynamic>? ?? {},
|
||||
),
|
||||
currentTask: _taskInfoFromJson(
|
||||
progressJson['taskInfo'] as Map<String, dynamic>? ??
|
||||
<String, dynamic>{},
|
||||
),
|
||||
plotStageCount: progressJson['plotStages'] as int? ?? 1,
|
||||
questCount: progressJson['questCount'] as int? ?? 0,
|
||||
),
|
||||
queue: QueueState(
|
||||
entries: Queue<QueueEntry>.from(
|
||||
queueJson.map((e) {
|
||||
final m = e as Map<String, dynamic>;
|
||||
final kind = QueueKind.values.firstWhere(
|
||||
(k) => k.name == m['kind'],
|
||||
orElse: () => QueueKind.task,
|
||||
);
|
||||
final taskType = TaskType.values.firstWhere(
|
||||
(t) => t.name == m['taskType'],
|
||||
orElse: () => TaskType.neutral,
|
||||
);
|
||||
return QueueEntry(
|
||||
kind: kind,
|
||||
durationMillis: m['duration'] as int? ?? 0,
|
||||
caption: m['caption'] as String? ?? '',
|
||||
taskType: taskType,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
GameState toState() {
|
||||
return GameState(
|
||||
rng: DeterministicRandom.fromState(rngState),
|
||||
traits: traits,
|
||||
stats: stats,
|
||||
inventory: inventory,
|
||||
equipment: equipment,
|
||||
spellBook: spellBook,
|
||||
progress: progress,
|
||||
queue: queue,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> _barToJson(ProgressBarState bar) => {
|
||||
'pos': bar.position,
|
||||
'max': bar.max,
|
||||
};
|
||||
|
||||
ProgressBarState _barFromJson(Map<String, dynamic> json) => ProgressBarState(
|
||||
position: json['pos'] as int? ?? 0,
|
||||
max: json['max'] as int? ?? 1,
|
||||
);
|
||||
|
||||
TaskInfo _taskInfoFromJson(Map<String, dynamic> json) {
|
||||
final typeName = json['type'] as String?;
|
||||
final type = TaskType.values.firstWhere(
|
||||
(t) => t.name == typeName,
|
||||
orElse: () => TaskType.neutral,
|
||||
);
|
||||
return TaskInfo(caption: json['caption'] as String? ?? '', type: type);
|
||||
}
|
||||
Reference in New Issue
Block a user