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
11 changes: 6 additions & 5 deletions bin/localization/data.csv

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions lib/core/objects/story_tile_preferences_object.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class StoryTilePreferencesObject {
final bool showPeopleLabels;
final bool showVoiceCount;
final bool showLocation;
final bool photoCollage;
final int displayCharacterCount;

StoryTilePreferencesObject({
Expand All @@ -21,13 +22,15 @@ class StoryTilePreferencesObject {
bool? showPeopleLabels,
bool? showVoiceCount,
bool? showLocation,
bool? photoCollage,
int? displayCharacterCount,
}) : showTime = showTime ?? true,
showPageCount = showPageCount ?? true,
showTagLabels = showTagLabels ?? true,
showPeopleLabels = showPeopleLabels ?? true,
showVoiceCount = showVoiceCount ?? true,
showLocation = showLocation ?? true,
photoCollage = photoCollage ?? false,
displayCharacterCount = displayCharacterCount ?? 200;

// During user editing, we can show all content without limit.
Expand Down
14 changes: 14 additions & 0 deletions lib/core/objects/story_tile_preferences_object.g.dart

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

2 changes: 1 addition & 1 deletion lib/views/day_colors/day_colors_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import 'package:storypad/providers/device_preferences_provider.dart';
import 'package:storypad/providers/in_app_purchase_provider.dart';
import 'package:storypad/views/paywall/paywall_view.dart';
import 'package:storypad/widgets/base_view/base_route.dart';
import 'package:storypad/widgets/sp_adaptive_pop_up_button.dart';
import 'package:storypad/widgets/sp_color_picker.dart';
import 'package:storypad/widgets/sp_floating_pop_up_button.dart';
import 'package:storypad/widgets/sp_icons.dart';
import 'package:storypad/widgets/sp_pop_up_menu_button.dart';
import 'package:storypad/widgets/sp_theme_mode_icon.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,17 @@ class DefaultStoryPreferencesTile extends StatelessWidget {
title: Text(tr("list_tile.default_story_preferences.title")),
trailing: locked ? const Icon(SpIcons.lock) : null,
onTap: () async {
final result = await const SpDefaultStoryPreferencesSheet().show(context: context);
if (context.mounted && result is DefaultStoryPreferencesObject) {
context.read<DevicePreferencesProvider>().setDefaultStoryPreferences(result);
// The sheet has no save button for pro users; it reports its live draft and
// we commit it once here, after the sheet closes.
DefaultStoryPreferencesObject? draft;
await SpDefaultStoryPreferencesSheet(onChanged: (result) => draft = result).show(context: context);

if (!context.mounted || draft == null) return;

// Non-pro users are gated by the locked save button inside the sheet (paywall),
// so their draft is never persisted here.
if (context.read<InAppPurchaseProvider>().isProUser) {
context.read<DevicePreferencesProvider>().setDefaultStoryPreferences(draft!);
}
},
);
Expand Down
13 changes: 10 additions & 3 deletions lib/views/settings/local_widgets/story_tile_preferences_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,21 @@ class StoryTilePreferencesTile extends StatelessWidget {
title: Text(tr("list_tile.story_tile_preferences.title")),
trailing: locked ? const Icon(SpIcons.lock) : null,
onTap: () async {
final result = await const SpStoryTilePreferencesSheet().show(context: context);
// The sheet has no save button for pro users; it reports its live draft and
// we commit it once here, after the sheet closes.
StoryTilePreferencesObject? draft;
await SpStoryTilePreferencesSheet(onChanged: (result) => draft = result).show(context: context);

// delay to ensure the bottom sheet is fully closed before applying the new preferences,
// which can trigger a rebuild of the story list and cause jank if done too early.
await Future.delayed(const Duration(milliseconds: 500));

if (context.mounted && result is StoryTilePreferencesObject) {
context.read<DevicePreferencesProvider>().setStoryTilePreferences(result);
if (!context.mounted || draft == null) return;

Comment thread
theachoem marked this conversation as resolved.
// Non-pro users are gated by the locked save button inside the sheet (paywall),
// so their draft is never persisted here.
if (context.read<InAppPurchaseProvider>().isProUser) {
context.read<DevicePreferencesProvider>().setStoryTilePreferences(draft!);
}
},
);
Expand Down
59 changes: 37 additions & 22 deletions lib/widgets/bottom_sheets/sp_default_story_preferences_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import 'package:storypad/widgets/sp_icons.dart';
import 'package:storypad/widgets/sp_layout_type_section.dart';

class SpDefaultStoryPreferencesSheet extends BaseBottomSheet {
const SpDefaultStoryPreferencesSheet();
const SpDefaultStoryPreferencesSheet({this.onChanged});

/// Reports the live draft on every change ([null] when nothing differs from
/// the saved value). The caller commits it after the sheet closes.
final void Function(DefaultStoryPreferencesObject? preferences)? onChanged;

@override
bool get fullScreen => true;
Expand All @@ -42,16 +46,19 @@ class SpDefaultStoryPreferencesSheet extends BaseBottomSheet {
Widget buildView(BuildContext context, double bottomPadding) {
return _StoryEditingPreferencesSheetContent(
bottomPadding: bottomPadding,
onChanged: onChanged,
);
}
}

class _StoryEditingPreferencesSheetContent extends StatefulWidget {
const _StoryEditingPreferencesSheetContent({
required this.bottomPadding,
this.onChanged,
});

final double bottomPadding;
final void Function(DefaultStoryPreferencesObject? preferences)? onChanged;

@override
State<_StoryEditingPreferencesSheetContent> createState() => _StoryEditingPreferencesSheetContentState();
Expand All @@ -68,6 +75,11 @@ class _StoryEditingPreferencesSheetContentState extends State<_StoryEditingPrefe
bool get resettable =>
jsonEncode(defaultStoryPreferences.toJson()) != jsonEncode(defaultStoryPreferencesDefault.toJson());

void _apply(DefaultStoryPreferencesObject next) {
setState(() => defaultStoryPreferences = next);
widget.onChanged?.call(changed ? defaultStoryPreferences : null);
}

@override
Widget build(BuildContext context) {
return Scaffold(
Expand All @@ -76,25 +88,28 @@ class _StoryEditingPreferencesSheetContentState extends State<_StoryEditingPrefe
title: Text(tr("list_tile.default_story_preferences.title")),
automaticallyImplyLeading: !CupertinoSheetRoute.hasParentSheet(context),
actions: [
if (changed)
// Pro users save automatically when the sheet closes, so no save button.
// Non-pro users keep a locked save button that opens the paywall; they can
// still preview changes but cannot persist them.
if (changed && !Provider.of<InAppPurchaseProvider>(context).isProUser)
IconButton(
tooltip: tr("button.done"),
icon: Icon(SpIcons.save, color: Theme.of(context).colorScheme.primary),
onPressed: changed
? () {
if (context.read<InAppPurchaseProvider>().isProUser) {
Navigator.maybePop(context, defaultStoryPreferences);
} else {
const PaywallRoute(initialFocus: .customizations).push(context);
}
}
: null,
icon: Stack(
clipBehavior: Clip.none,
children: [
Icon(SpIcons.save, color: Theme.of(context).colorScheme.primary),
const Positioned(
top: -2,
right: -8,
child: Icon(SpIcons.lock, size: 12.0),
),
],
),
onPressed: () => const PaywallRoute(initialFocus: .customizations).push(context),
),
IconButton(
icon: const Icon(SpIcons.refresh),
onPressed: resettable
? () => setState(() => defaultStoryPreferences = defaultStoryPreferencesDefault)
: null,
onPressed: resettable ? () => _apply(defaultStoryPreferencesDefault) : null,
),
if (CupertinoSheetRoute.hasParentSheet(context))
CloseButton(onPressed: () => CupertinoSheetRoute.popSheet(context)),
Expand All @@ -110,20 +125,20 @@ class _StoryEditingPreferencesSheetContentState extends State<_StoryEditingPrefe
colorTone: defaultStoryPreferences.defaultColorTone,
backgroundImagePath: defaultStoryPreferences.defaultBackgroundImagePath,
onThemeChanged: ({colorSeedValue, colorTone, backgroundImagePath}) {
defaultStoryPreferences = defaultStoryPreferences.copyWith(
defaultColorSeedValue: colorSeedValue,
defaultColorTone: colorTone,
defaultBackgroundImagePath: backgroundImagePath,
_apply(
defaultStoryPreferences.copyWith(
defaultColorSeedValue: colorSeedValue,
defaultColorTone: colorTone,
defaultBackgroundImagePath: backgroundImagePath,
),
);
setState(() {});
},
),
const SizedBox(height: 12.0),
SpLayoutTypeSection(
selected: defaultStoryPreferences.defaultLayoutType,
onThemeChanged: (layoutType) {
defaultStoryPreferences = defaultStoryPreferences.copyWith(defaultLayoutType: layoutType);
setState(() {});
_apply(defaultStoryPreferences.copyWith(defaultLayoutType: layoutType));
},
),
SizedBox(height: widget.bottomPadding),
Expand Down
Loading
Loading