Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions lib/hive/hive_adapters.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion lib/hive/hive_adapters.g.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ types:
index: 4
AppPreferences:
typeId: 28
nextIndex: 17
nextIndex: 18
fields:
defaultThemeProfileIdForNewStrategies:
index: 0
Expand Down Expand Up @@ -477,6 +477,8 @@ types:
index: 14
drawingThickness:
index: 15
discordPresenceEnabled:
index: 17
PlacedViewConeAgent:
typeId: 29
nextIndex: 10
Expand Down
72 changes: 72 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ import 'package:icarus/const/routes.dart';
import 'package:icarus/const/second_instance_args.dart';
import 'package:icarus/const/settings.dart' show Settings;
import 'package:icarus/hive/hive_registration.dart';
import 'package:icarus/const/placed_classes.dart';
import 'package:icarus/providers/ability_provider.dart';
import 'package:icarus/providers/agent_provider.dart';
import 'package:icarus/providers/folder_provider.dart';
import 'package:icarus/providers/map_provider.dart';
import 'package:icarus/providers/user_preferences_provider.dart';
import 'package:icarus/providers/strategy_provider.dart';
import 'package:icarus/services/app_error_reporter.dart';
import 'package:icarus/services/analytics_service.dart';
import 'package:icarus/services/discord_presence_service.dart';
import 'package:icarus/strategy_view.dart';
import 'package:icarus/widgets/folder_navigator.dart';
import 'package:icarus/widgets/global_shortcuts.dart';
Expand Down Expand Up @@ -217,6 +222,13 @@ class MyApp extends ConsumerStatefulWidget {

class _MyAppState extends ConsumerState<MyApp> {
StreamSubscription<List<String>>? _secondInstanceSub;
late final DiscordPresenceService _discordPresence;
ProviderSubscription<StrategyState>? _discordStrategySub;
ProviderSubscription<MapState>? _discordMapSub;
ProviderSubscription<AppPreferences>? _discordPreferencesSub;
ProviderSubscription<List<PlacedAgentNode>>? _discordAgentSub;
ProviderSubscription<List<PlacedAbility>>? _discordAbilitySub;
Timer? _discordSyncDebounce;

Future<void> _loadFromFilePathWithWarning(String filePath) async {
try {
Expand All @@ -235,6 +247,30 @@ class _MyAppState extends ConsumerState<MyApp> {
void initState() {
super.initState();

_discordPresence = DiscordPresenceService();
_discordStrategySub = ref.listenManual(
strategyProvider,
(_, __) => _scheduleDiscordSync(),
);
_discordMapSub = ref.listenManual(
mapProvider,
(_, __) => _scheduleDiscordSync(),
);
_discordAgentSub = ref.listenManual(
agentProvider,
(_, __) => _scheduleDiscordSync(),
);
_discordAbilitySub = ref.listenManual(
abilityProvider,
(_, __) => _scheduleDiscordSync(),
);
_discordPreferencesSub = ref.listenManual(
appPreferencesProvider,
(_, __) => _syncDiscordPresence(),
);

unawaited(_syncDiscordPresence());

WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.data.isEmpty) return;

Expand Down Expand Up @@ -263,9 +299,45 @@ class _MyAppState extends ConsumerState<MyApp> {
@override
void dispose() {
_secondInstanceSub?.cancel();
_discordSyncDebounce?.cancel();
_discordStrategySub?.close();
_discordMapSub?.close();
_discordAgentSub?.close();
_discordAbilitySub?.close();
_discordPreferencesSub?.close();
unawaited(_discordPresence.dispose());
super.dispose();
}

/// Coalesces rapid state changes (e.g. placing several agents in a row)
/// into one presence update, keeping well under Discord's rate limit.
void _scheduleDiscordSync() {
_discordSyncDebounce?.cancel();
_discordSyncDebounce = Timer(
const Duration(seconds: 2),
() => unawaited(_syncDiscordPresence()),
);
}

Future<void> _syncDiscordPresence() async {
if (!mounted) return;

final preferences = ref.read(appPreferencesProvider);
if (!preferences.discordPresenceEnabled) {
await _discordPresence.clear();
return;
}

await _discordPresence.update(
DiscordPresenceData.fromAppState(
strategy: ref.read(strategyProvider),
map: ref.read(mapProvider),
agentCount: ref.read(agentProvider).length,
abilityCount: ref.read(abilityProvider).length,
),
);
}

@override
Widget build(BuildContext context) {
return ToastificationWrapper(
Expand Down
11 changes: 11 additions & 0 deletions lib/providers/user_preferences_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class AppPreferences extends HiveObject {
final String librarySortOrderName;
final int drawingColorValue;
final double drawingThickness;
final bool discordPresenceEnabled;

AppPreferences({
required this.defaultThemeProfileIdForNewStrategies,
Expand All @@ -144,6 +145,7 @@ class AppPreferences extends HiveObject {
this.librarySortOrderName = 'ascending',
this.drawingColorValue = 0xFFFFFFFF,
this.drawingThickness = Settings.defaultStrokeThickness,
this.discordPresenceEnabled = true,
}) : customColorValues = List.unmodifiable(customColorValues ?? const []),
customShortcutBindings =
Map.unmodifiable(customShortcutBindings ?? const {});
Expand All @@ -165,6 +167,7 @@ class AppPreferences extends HiveObject {
String? librarySortOrderName,
int? drawingColorValue,
double? drawingThickness,
bool? discordPresenceEnabled,
}) {
return AppPreferences(
defaultThemeProfileIdForNewStrategies:
Expand All @@ -191,6 +194,8 @@ class AppPreferences extends HiveObject {
librarySortOrderName: librarySortOrderName ?? this.librarySortOrderName,
drawingColorValue: drawingColorValue ?? this.drawingColorValue,
drawingThickness: drawingThickness ?? this.drawingThickness,
discordPresenceEnabled:
discordPresenceEnabled ?? this.discordPresenceEnabled,
);
}
}
Expand Down Expand Up @@ -553,6 +558,12 @@ class AppPreferencesNotifier extends Notifier<AppPreferences> {
);
}

Future<void> setDiscordPresenceEnabled(bool enabled) {
return _updatePreferences(
(current) => current.copyWith(discordPresenceEnabled: enabled),
);
}

Future<void> setShowSpawnBarrier(bool visible) {
return _updatePreferences(
(current) => current.copyWith(showSpawnBarrier: visible),
Expand Down
Loading
Loading