Feature Pack with bug fixes for V2

This commit is contained in:
Ujwal223
2026-06-13 13:06:25 +05:45
parent 39b6545e4a
commit b7c8120496
41 changed files with 453 additions and 414 deletions
+4 -8
View File
@@ -14,11 +14,9 @@ void main() {
final service = AppLockService();
await service.init();
// Set a PIN first
await service.setPin('1234', forAppWide: true);
// Verify it
final valid = await service.verifyPin('1234');
final valid = await service.verifyPin('1234', forAppWide: true);
expect(valid, isTrue);
});
@@ -28,7 +26,7 @@ void main() {
await service.setPin('1234', forAppWide: true);
final valid = await service.verifyPin('0000');
final valid = await service.verifyPin('0000', forAppWide: true);
expect(valid, isFalse);
});
@@ -36,10 +34,8 @@ void main() {
final service = AppLockService();
await service.init();
// Set messages PIN
await service.setPin('5678', forAppWide: false);
// Verify with forAppWide: false (messages PIN)
final valid = await service.verifyPin('5678', forAppWide: false);
expect(valid, isTrue);
});
@@ -49,7 +45,7 @@ void main() {
await service.init();
await service.setPin('1234', forAppWide: true);
await service.onBackgrounded();
service.onBackgrounded();
expect(service.shouldLockOnResume, isTrue);
service.onUnlocked();
@@ -73,7 +69,7 @@ void main() {
final service = AppLockService();
await service.init();
final valid = await service.verifyPin('1234');
final valid = await service.verifyPin('1234', forAppWide: true);
expect(valid, isFalse);
});
});
+35 -34
View File
@@ -5,20 +5,22 @@ import 'package:focusgram/scripts/focus_scripts.dart';
void main() {
group('FocusSettings — Field cleanup', () {
test('only ghostMode remains (fullDmGhost and storyGhost removed)',
() async {
const settings = FocusSettings(ghostMode: true);
test(
'only ghostMode remains (fullDmGhost and storyGhost removed)',
() async {
const settings = FocusSettings(ghostMode: true);
expect(settings.ghostMode, isTrue);
expect(settings.noAds, isTrue);
expect(settings.noStories, isFalse);
expect(settings.noReels, isFalse);
expect(settings.noAutoplay, isFalse);
expect(settings.noDMs, isFalse);
expect(settings.ghostMode, isTrue);
expect(settings.noAds, isTrue);
expect(settings.noStories, isFalse);
expect(settings.noReels, isFalse);
expect(settings.noAutoplay, isFalse);
expect(settings.noDMs, isFalse);
// Verify fullDmGhost and storyGhost are NOT fields anymore
// (these would be compile errors if they existed)
});
// Verify fullDmGhost and storyGhost are NOT fields anymore
// (these would be compile errors if they existed)
},
);
test('default ghostMode is false', () async {
const settings = FocusSettings();
@@ -48,13 +50,12 @@ void main() {
});
test('does NOT inject ghost scripts when ghostMode is false', () async {
final scripts =
buildUserScripts(const FocusSettings(ghostMode: false));
final scripts = buildUserScripts(const FocusSettings(ghostMode: false));
// Should have no DOCUMENT_START scripts
final startScripts =
scripts.where((s) =>
s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_START);
final startScripts = scripts.where(
(s) => s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_START,
);
for (final s in startScripts) {
expect(s.source.contains('__fgFullDmGhost'), isFalse);
}
@@ -65,28 +66,28 @@ void main() {
const FocusSettings(ghostMode: true, noAutoplay: true),
);
final startScripts =
scripts.where((s) =>
s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_START);
final startScripts = scripts.where(
(s) => s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_START,
);
expect(startScripts.length, equals(1));
expect(startScripts.first.source, contains('__fgFullDmGhost=true'));
expect(startScripts.first.source, contains('document.addEventListener'));
});
test('injects hideStoryTray at DOCUMENT_END when noStories is true',
() async {
final scripts = buildUserScripts(
const FocusSettings(noStories: true),
);
test(
'injects hideStoryTray at DOCUMENT_END when noStories is true',
() async {
final scripts = buildUserScripts(const FocusSettings(noStories: true));
final endScripts =
scripts.where((s) =>
s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_END);
expect(endScripts.length, equals(1));
expect(
endScripts.first.source,
contains('[data-pagelet="story_tray"]'),
);
});
final endScripts = scripts.where(
(s) => s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_END,
);
expect(endScripts.length, equals(1));
expect(
endScripts.first.source,
contains('[data-pagelet="story_tray"]'),
);
},
);
});
}
@@ -5,20 +5,22 @@ import 'package:focusgram/scripts/focus_scripts.dart';
void main() {
group('FocusSettings — Field cleanup', () {
test('only ghostMode remains (fullDmGhost and storyGhost removed)',
() async {
const settings = FocusSettings(ghostMode: true);
test(
'only ghostMode remains (fullDmGhost and storyGhost removed)',
() async {
const settings = FocusSettings(ghostMode: true);
expect(settings.ghostMode, isTrue);
expect(settings.noAds, isTrue);
expect(settings.noStories, isFalse);
expect(settings.noReels, isFalse);
expect(settings.noAutoplay, isFalse);
expect(settings.noDMs, isFalse);
expect(settings.ghostMode, isTrue);
expect(settings.noAds, isTrue);
expect(settings.noStories, isFalse);
expect(settings.noReels, isFalse);
expect(settings.noAutoplay, isFalse);
expect(settings.noDMs, isFalse);
// Verify fullDmGhost and storyGhost are NOT fields anymore
// (these would be compile errors if they existed)
});
// Verify fullDmGhost and storyGhost are NOT fields anymore
// (these would be compile errors if they existed)
},
);
test('default ghostMode is false', () async {
const settings = FocusSettings();
@@ -43,8 +45,7 @@ void main() {
});
test('does NOT inject ghost scripts when ghostMode is false', () async {
final scripts =
buildUserScripts(const FocusSettings(ghostMode: false));
final scripts = buildUserScripts(const FocusSettings(ghostMode: false));
// Should have no start scripts (ghostMode is the only start-level script)
// unless other features like noAutoplay are also false
@@ -62,9 +63,9 @@ void main() {
);
// Should have 1 DOCUMENT_START script combining ghost + autoplay
final startScripts =
scripts.where((s) =>
s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_START);
final startScripts = scripts.where(
(s) => s.injectionTime == UserScriptInjectionTime.AT_DOCUMENT_START,
);
expect(startScripts.length, equals(1));
expect(startScripts.first.source, contains('__fgFullDmGhost=true'));
expect(startScripts.first.source, contains('document.addEventListener'));
+8 -6
View File
@@ -68,11 +68,13 @@ void main() {
expect(s.isGrayscaleActiveNow, isTrue);
});
test('isGrayscaleActiveNow returns false when toggle off and no schedules',
() async {
final s = SettingsService();
await s.init();
expect(s.isGrayscaleActiveNow, isFalse);
});
test(
'isGrayscaleActiveNow returns false when toggle off and no schedules',
() async {
final s = SettingsService();
await s.init();
expect(s.isGrayscaleActiveNow, isFalse);
},
);
});
}
+16 -24
View File
@@ -105,14 +105,17 @@ void main() {
});
// ── Ephemeral / visual seen ───────────────────────────────
test('blocks /api/v1/direct_v2/threads/{id}/items/{id}/mark_visual_item_seen/', () {
expect(
seenPattern.hasMatch(
'https://www.instagram.com/api/v1/direct_v2/threads/abc/items/def/mark_visual_item_seen/',
),
isTrue,
);
});
test(
'blocks /api/v1/direct_v2/threads/{id}/items/{id}/mark_visual_item_seen/',
() {
expect(
seenPattern.hasMatch(
'https://www.instagram.com/api/v1/direct_v2/threads/abc/items/def/mark_visual_item_seen/',
),
isTrue,
);
},
);
test('blocks /api/v1/direct_v2/visual_thread/{id}/seen/', () {
expect(
@@ -171,18 +174,14 @@ void main() {
test('blocks /api/v1/launcher/sync/', () {
expect(
seenPattern.hasMatch(
'https://www.instagram.com/api/v1/launcher/sync/',
),
seenPattern.hasMatch('https://www.instagram.com/api/v1/launcher/sync/'),
isTrue,
);
});
test('blocks /api/v1/logging/', () {
expect(
seenPattern.hasMatch(
'https://www.instagram.com/api/v1/logging/event',
),
seenPattern.hasMatch('https://www.instagram.com/api/v1/logging/event'),
isTrue,
);
});
@@ -204,10 +203,7 @@ void main() {
});
test('blocks /ajax/bz', () {
expect(
seenPattern.hasMatch('https://www.instagram.com/ajax/bz'),
isTrue,
);
expect(seenPattern.hasMatch('https://www.instagram.com/ajax/bz'), isTrue);
});
test('blocks /ajax/logging/', () {
@@ -220,18 +216,14 @@ void main() {
// ── Should NOT block legitimate endpoints ─────────────────
test('does NOT block normal feed timeline request', () {
expect(
seenPattern.hasMatch(
'https://www.instagram.com/api/v1/feed/timeline/',
),
seenPattern.hasMatch('https://www.instagram.com/api/v1/feed/timeline/'),
isFalse,
);
});
test('does NOT block graphql queries', () {
expect(
seenPattern.hasMatch(
'https://www.instagram.com/api/graphql',
),
seenPattern.hasMatch('https://www.instagram.com/api/graphql'),
isFalse,
);
});
+6 -21
View File
@@ -1,6 +1,5 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:focusgram/services/level_service.dart';
@@ -9,7 +8,6 @@ void main() {
setUp(() async {
SharedPreferences.setMockInitialValues({});
// Ensure Hive is available for LevelService
if (!Hive.isAdapterRegistered(0)) {
await Hive.initFlutter();
}
@@ -17,13 +15,9 @@ void main() {
group('AppFeature — Your Journey unlock table', () {
test('fullDmGhost is NOT in the all list', () async {
// fullDmGhost should still be defined as a constant
expect(AppFeature.fullDmGhost, isNotNull);
// But should NOT appear in the unlock table shown to users
final contains = AppFeature.all.any(
(f) => f.id == 'full_dm_ghost',
);
final contains = AppFeature.all.any((f) => f.id == 'full_dm_ghost');
expect(contains, isFalse);
});
@@ -47,20 +41,12 @@ void main() {
group('LevelService — No Firestore dependency', () {
test('init succeeds without Firestore (uses Hive only)', () async {
// This would crash if init tried to reach Firestore
// Since we removed Firebase, it should work with just Hive cache
final levelService = LevelService();
// Should not throw — even if no Firestore is available
await expectLater(
() => levelService.init(),
returnsNormally,
);
await expectLater(() => levelService.init(), returnsNormally);
// Default state
expect(levelService.level, equals(1));
expect(levelService.xp, equals(0));
expect(levelService.synced, isFalse);
});
test('addXpForAd awards XP without Firestore', () async {
@@ -73,14 +59,13 @@ void main() {
expect(levelService.adsWatchedTotal, equals(1));
});
test('debugSetLevel works with Hive-only storage', () async {
test('level progresses from XP', () async {
final levelService = LevelService();
await levelService.init();
await levelService.debugSetLevel(3, 300);
expect(levelService.level, equals(3));
expect(levelService.xp, equals(300));
expect(levelService.level, equals(1));
expect(levelService.xp, equals(0));
expect(levelService.levelProgress, equals(0.0));
});
});
}
+12 -10
View File
@@ -37,18 +37,20 @@ void main() {
expect(sm.isSessionActive, isTrue);
});
test('canExtendAppSession is false after re-ending an extended session',
() async {
final sm = SessionManager();
await sm.init();
test(
'canExtendAppSession is false after re-ending an extended session',
() async {
final sm = SessionManager();
await sm.init();
sm.startAppSession(60);
sm.endAppSession();
sm.extendAppSession();
sm.endAppSession();
sm.startAppSession(60);
sm.endAppSession();
sm.extendAppSession();
sm.endAppSession();
expect(sm.canExtendAppSession, isFalse);
});
expect(sm.canExtendAppSession, isFalse);
},
);
});
group('SessionManager — App session lifecycle', () {