Skip to content

Commit

Permalink
feat: offline experience (#83)
Browse files Browse the repository at this point in the history
* chore: improve analytics when app is disconnected

* feat: get data from cache if request fails

* feat: show custom bestiaries dinamically
  • Loading branch information
VytorCalixto authored Dec 14, 2024
1 parent b4aabaf commit f056c5f
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 49 deletions.
4 changes: 4 additions & 0 deletions lib/api/services/dnd5e_bestiary_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ class Dnd5eBestiaryService extends BestiaryService {
);
} on DioException catch (e) {
logger.e(e);
if (cache != null) {
logger.d('Request failed. Retrieving from cache');
data = await decodeCache(cache) ?? [];
}
}

data.sort((a, b) => a.name.compareTo(b.name));
Expand Down
4 changes: 4 additions & 0 deletions lib/api/services/dnd5e_condition_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class Dnd5eConditionService extends DataService<List<Condition>> {
data.addAll(results.map(Condition.from5e));
} on DioException catch (e) {
logger.e(e);
if (cache != null) {
logger.d('Request failed. Retrieving from cache');
data = await decodeCache(cache) ?? [];
}
}

data.sort((a, b) => a.name.compareTo(b.name));
Expand Down
12 changes: 11 additions & 1 deletion lib/api/services/pf2e_bestiary_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ class Pf2eBestiaryService extends BestiaryService {
return data;
}

await _getAvailableSources();
try {
await _getAvailableSources();
} on DioException catch (e) {
logger.e(e);
}

for (final source in bestiarySources) {
logger.d('Fetching bestiary data for $source');
final sourceUri = _availableSources[source];
Expand Down Expand Up @@ -80,6 +85,11 @@ class Pf2eBestiaryService extends BestiaryService {
}
}

if (data.isEmpty && cache != null) {
logger.d('Request failed. Retrieving from cache');
data = await decodeCache(cache) ?? [];
}

data.sort((a, b) => a.name.compareTo(b.name));
if (data.isNotEmpty) {
logger.d('Caching bestiary data');
Expand Down
4 changes: 4 additions & 0 deletions lib/api/services/pf2e_condition_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ class Pf2eConditionService extends DataService<List<Condition>> {
data.addAll(results.map(Condition.fromPf2e));
} on DioException catch (e) {
logger.e(e);
if (cache != null) {
logger.d('Request failed. Retrieving from cache');
data = await decodeCache(cache) ?? [];
}
}

data.sort((a, b) => a.name.compareTo(b.name));
Expand Down
78 changes: 44 additions & 34 deletions lib/features/combatant/widgets/add_combatant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,43 @@ class AddCombatant extends StatelessWidget {

@override
Widget build(BuildContext context) {
final systemSettings = context.watch<SystemSettingsProvider>();
var localization = AppLocalizations.of(context)!;
final isMobile = ResponsiveBreakpoints.of(context).isMobile;

final tabs = <Tab, Widget>{
return StreamBuilder<List<CustomBestiary>>(
stream: context.read<CustomBestiaryProvider>().watchAll(),
builder: (context, snapshot) {
final data = snapshot.data ?? [];
final tabs = getTabs(context, data);
return DefaultTabController(
length: tabs.length,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TabBar(
tabs: tabs.keys.toList(),
isScrollable: isMobile && tabs.length > 3,
),
const SizedBox(height: 8),
Expanded(
child: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: tabs.values.toList(),
),
),
],
),
),
);
});
}

Map<Tab, Widget> getTabs(
BuildContext context, List<CustomBestiary> customBestiaries) {
final systemSettings = context.watch<SystemSettingsProvider>();
final localization = AppLocalizations.of(context)!;
return <Tab, Widget>{
if (systemSettings.dnd5eSettings.enabled)
Tab(
text: localization.dnd5e_toggle_button,
Expand All @@ -55,13 +87,13 @@ class AddCombatant extends StatelessWidget {
.logEvent('add_pf2e_combatant');
},
),
Tab(
text: localization.custom_bestiary_toggle_button,
icon: Icon(MingCute.paw_fill),
): StreamBuilder<List<CustomBestiary>>(
stream: context.read<CustomBestiaryProvider>().watchAll(),
builder: (context, snapshot) {
final data = snapshot.data ?? [];
if (customBestiaries.isNotEmpty)
Tab(
text: localization.custom_bestiary_toggle_button,
icon: Icon(MingCute.paw_fill),
): Builder(
builder: (context) {
final data = customBestiaries;
return AddFromBestiaryList(
combatants: data.fold(
[],
Expand All @@ -75,7 +107,8 @@ class AddCombatant extends StatelessWidget {
.logEvent('add_custom_bestiary_combatant');
},
);
}),
},
),
Tab(
text: localization.groups_toggle_button,
icon: Icon(MingCute.group_fill),
Expand Down Expand Up @@ -108,28 +141,5 @@ class AddCombatant extends StatelessWidget {
},
),
};

return DefaultTabController(
length: tabs.length,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TabBar(
tabs: tabs.keys.toList(),
isScrollable: isMobile && tabs.length > 3,
),
const SizedBox(height: 8),
Expanded(
child: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: tabs.values.toList(),
),
),
],
),
),
);
}
}
10 changes: 5 additions & 5 deletions lib/features/combatant/widgets/add_custom_combatant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,15 @@ class _GroupReminder extends StatelessWidget {
.read<EncountersProvider>()
.addEncounter(encounter);
// ignore: use_build_context_synchronously
await context.read<AnalyticsService>().logEvent(
'create-encounter',
props: {'type': EncounterType.group.toString()},
);
// ignore: use_build_context_synchronously
context.pushNamed(
"group",
pathParameters: {"groupId": created.id.toString()},
);
// ignore: use_build_context_synchronously
await context.read<AnalyticsService>().logEvent(
'create-encounter',
props: {'type': EncounterType.group.toString()},
);
},
child: Text(localization.create_group_cta),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,6 @@ class _RecallKnowledge extends StatelessWidget {
@override
Widget build(BuildContext context) {
final localization = AppLocalizations.of(context)!;
// FIXME: textos
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expand Down
4 changes: 2 additions & 2 deletions lib/features/encounters/widgets/encounter_tile_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ class EncounterTileMenu extends StatelessWidget {
},
onSelected: (value) async {
if (value == EncounterMenuOptions.deleteCombat) {
await context.read<AnalyticsService>().logEvent('delete-encounter');
// ignore: use_build_context_synchronously
await context.read<EncountersProvider>().removeEncounter(encounter);
// ignore: use_build_context_synchronously
await context.read<AnalyticsService>().logEvent('delete-encounter');
return;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/features/encounters/widgets/encounters_grid.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class EncountersGrid extends StatelessWidget {
.read<EncountersProvider>()
.addEncounter(encounter);
// ignore: use_build_context_synchronously
await context.read<AnalyticsService>().logEvent(
context.read<AnalyticsService>().logEvent(
'create-encounter',
props: {'type': type.toString()},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class SystemSettingsProvider extends ChangeNotifier {
baseURI: const String.fromEnvironment('FLAGSMITH_URI'),
isDebug: kDebugMode,
enableAnalytics: true,
enableRealtimeUpdates: true,
),
) {
_init();
Expand Down
9 changes: 5 additions & 4 deletions lib/features/settings/widgets/custom_bestiaries_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ class CustomBestiariesSettings extends StatelessWidget {
try {
final result =
await bestiaryState.create(bestiaryFile);
analytics.logEvent(
'bestiary_imported',
props: {'engine': bestiaryFile.engine.toString()},
);

toastification.show(
type: result.hasFailed
? ToastificationType.warning
Expand All @@ -65,6 +62,10 @@ class CustomBestiariesSettings extends StatelessWidget {
.bestiary_import_warning_description)
: null,
);
analytics.logEvent(
'bestiary_imported',
props: {'engine': bestiaryFile.engine.toString()},
);
} catch (e) {
Logger().e(e);
toastification.show(
Expand Down

0 comments on commit f056c5f

Please sign in to comment.