@@ -23,7 +23,7 @@ class DatabaseHelper {
2323
2424 return await openDatabase (
2525 path,
26- version: 5 ,
26+ version: 6 ,
2727 onCreate: _createDB,
2828 onUpgrade: _upgradeDB,
2929 );
@@ -62,13 +62,57 @@ class DatabaseHelper {
6262 whereArgs: [10 , 45 , 48 ],
6363 );
6464 }
65+
66+ if (oldVersion < 6 ) {
67+ // Migrate level_id from INTEGER to TEXT to support fractional levels (0.1, 0.2, etc.)
68+ // Also migrate level 0 to 0.1 for users who already completed it
69+
70+ // Create new tables with TEXT level_id
71+ await db.execute ('''
72+ CREATE TABLE completed_levels_new (
73+ level_id TEXT PRIMARY KEY,
74+ completed_at TEXT NOT NULL,
75+ moves_count INTEGER NOT NULL
76+ )
77+ ''' );
78+
79+ await db.execute ('''
80+ CREATE TABLE saved_games_new (
81+ level_id TEXT PRIMARY KEY,
82+ board_state TEXT NOT NULL,
83+ moves_count INTEGER NOT NULL,
84+ saved_at TEXT NOT NULL
85+ )
86+ ''' );
87+
88+ // Migrate data, converting level 0 to 0.1
89+ await db.execute ('''
90+ INSERT INTO completed_levels_new (level_id, completed_at, moves_count)
91+ SELECT CASE WHEN level_id = 0 THEN '0.1' ELSE CAST(level_id AS TEXT) END,
92+ completed_at, moves_count
93+ FROM completed_levels
94+ ''' );
95+
96+ await db.execute ('''
97+ INSERT INTO saved_games_new (level_id, board_state, moves_count, saved_at)
98+ SELECT CASE WHEN level_id = 0 THEN '0.1' ELSE CAST(level_id AS TEXT) END,
99+ board_state, moves_count, saved_at
100+ FROM saved_games
101+ ''' );
102+
103+ // Drop old tables and rename new ones
104+ await db.execute ('DROP TABLE completed_levels' );
105+ await db.execute ('DROP TABLE saved_games' );
106+ await db.execute ('ALTER TABLE completed_levels_new RENAME TO completed_levels' );
107+ await db.execute ('ALTER TABLE saved_games_new RENAME TO saved_games' );
108+ }
65109 }
66110
67111 Future <void > _createDB (Database db, int version) async {
68112 // Table for completed levels
69113 await db.execute ('''
70114 CREATE TABLE completed_levels (
71- level_id INTEGER PRIMARY KEY,
115+ level_id TEXT PRIMARY KEY,
72116 completed_at TEXT NOT NULL,
73117 moves_count INTEGER NOT NULL
74118 )
@@ -77,7 +121,7 @@ class DatabaseHelper {
77121 // Table for saved game states
78122 await db.execute ('''
79123 CREATE TABLE saved_games (
80- level_id INTEGER PRIMARY KEY,
124+ level_id TEXT PRIMARY KEY,
81125 board_state TEXT NOT NULL,
82126 moves_count INTEGER NOT NULL,
83127 saved_at TEXT NOT NULL
@@ -87,7 +131,7 @@ class DatabaseHelper {
87131
88132 // Completed Levels
89133 Future <void > markLevelCompleted ({
90- required int levelId,
134+ required String levelId,
91135 required int movesCount,
92136 }) async {
93137 final db = await database;
@@ -98,7 +142,7 @@ class DatabaseHelper {
98142 }, conflictAlgorithm: ConflictAlgorithm .replace);
99143 }
100144
101- Future <bool > isLevelCompleted (int levelId) async {
145+ Future <bool > isLevelCompleted (String levelId) async {
102146 final db = await database;
103147 final result = await db.query (
104148 'completed_levels' ,
@@ -108,15 +152,15 @@ class DatabaseHelper {
108152 return result.isNotEmpty;
109153 }
110154
111- Future <List <int >> getCompletedLevelIds () async {
155+ Future <List <String >> getCompletedLevelIds () async {
112156 final db = await database;
113157 final result = await db.query ('completed_levels' );
114- return result.map ((row) => row['level_id' ] as int ).toList ();
158+ return result.map ((row) => row['level_id' ] as String ).toList ();
115159 }
116160
117161 // Saved Game States
118162 Future <void > saveGameState ({
119- required int levelId,
163+ required String levelId,
120164 required List <List <String >> board,
121165 required int movesCount,
122166 }) async {
@@ -129,7 +173,7 @@ class DatabaseHelper {
129173 }, conflictAlgorithm: ConflictAlgorithm .replace);
130174 }
131175
132- Future <Map <String , dynamic >?> getSavedGameState (int levelId) async {
176+ Future <Map <String , dynamic >?> getSavedGameState (String levelId) async {
133177 final db = await database;
134178 final result = await db.query (
135179 'saved_games' ,
@@ -142,14 +186,14 @@ class DatabaseHelper {
142186 try {
143187 final row = result.first;
144188 final boardData = jsonDecode (row['board_state' ] as String ) as List <dynamic >;
145-
189+
146190 // Validate board structure
147191 if (boardData.isEmpty || boardData.first is ! List ) {
148192 // Invalid board structure, delete corrupted save
149193 await deleteSavedGameState (levelId);
150194 return null ;
151195 }
152-
196+
153197 return {
154198 'board' : boardData,
155199 'moves_count' : row['moves_count' ] as int ,
@@ -161,7 +205,7 @@ class DatabaseHelper {
161205 }
162206 }
163207
164- Future <void > deleteSavedGameState (int levelId) async {
208+ Future <void > deleteSavedGameState (String levelId) async {
165209 final db = await database;
166210 await db.delete ('saved_games' , where: 'level_id = ?' , whereArgs: [levelId]);
167211 }
@@ -172,7 +216,7 @@ class DatabaseHelper {
172216 }
173217
174218 /// Clear saved games for specific levels (useful after level modifications)
175- Future <void > clearSavedGamesForLevels (List <int > levelIds) async {
219+ Future <void > clearSavedGamesForLevels (List <String > levelIds) async {
176220 if (levelIds.isEmpty) return ;
177221 final db = await database;
178222 final placeholders = List .filled (levelIds.length, '?' ).join (',' );
0 commit comments