Add ability to toggle off the spoiler alert/CW system app wide

Implements Feature Request #42
This commit is contained in:
Hank Grabowski 2024-06-27 20:03:54 -04:00
parent 6504277005
commit f8ac2a05c0
8 changed files with 53 additions and 9 deletions

View file

@ -32,6 +32,8 @@
* Notifications are grouped by type, starting with mentions, within the unread and read groupings of the
notification list. Defaults to on by default but can be toggled off in
settings.([Feature #65](https://gitlab.com/mysocialportal/relatica/-/issues/65))
* Ability to turn off Spoiler Alert/CWs at the application
level. Defaults to on. ([Feature #42](https://gitlab.com/mysocialportal/relatica/-/issues/42))
## Version 0.10.1 (beta)

View file

@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import '../globals.dart';
import '../models/timeline_entry.dart';
import '../services/auth_service.dart';
import '../services/setting_service.dart';
import '../utils/clipboard_utils.dart';
import '../utils/url_opening_utils.dart';
import 'html_text_viewer_control.dart';
@ -27,6 +29,7 @@ class SearchResultStatusControl extends StatefulWidget {
}
class _SearchResultStatusControlState extends State<SearchResultStatusControl> {
var showSpoilerControl = true;
var showContent = false;
TimelineEntry get status => widget.status;
@ -34,7 +37,9 @@ class _SearchResultStatusControlState extends State<SearchResultStatusControl> {
@override
void initState() {
super.initState();
showContent = widget.status.spoilerText.isEmpty;
showSpoilerControl = getIt<SettingsService>().spoilerHidingEnabled;
showContent =
!showSpoilerControl ? true : widget.status.spoilerText.isEmpty;
}
@override
@ -77,7 +82,7 @@ class _SearchResultStatusControlState extends State<SearchResultStatusControl> {
const VerticalPadding(
height: 5,
),
if (status.spoilerText.isNotEmpty)
if (showSpoilerControl && status.spoilerText.isNotEmpty)
TextButton(
onPressed: () {
setState(() {
@ -85,7 +90,7 @@ class _SearchResultStatusControlState extends State<SearchResultStatusControl> {
});
},
child: Text(
'Content Summary: ${status.spoilerText} (Click to ${showContent ? "Hide" : "Show"}}')),
'Content Summary: ${status.spoilerText} (Click to ${showContent ? "Hide" : "Show"})')),
if (showContent) ...[
buildBody(context),
const VerticalPadding(

View file

@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:relatica/utils/snackbar_builder.dart';
import 'package:result_monad/result_monad.dart';
import '../../globals.dart';
@ -13,6 +12,7 @@ import '../../models/filters/timeline_entry_filter.dart';
import '../../models/flattened_tree_item.dart';
import '../../models/timeline_entry.dart';
import '../../services/auth_service.dart';
import '../../services/setting_service.dart';
import '../../services/timeline_entry_filter_service.dart';
import '../../services/timeline_manager.dart';
import '../../utils/active_profile_selector.dart';
@ -20,6 +20,7 @@ import '../../utils/clipboard_utils.dart';
import '../../utils/filter_runner.dart';
import '../../utils/html_to_edit_text_helper.dart';
import '../../utils/responsive_sizes_calculator.dart';
import '../../utils/snackbar_builder.dart';
import '../../utils/url_opening_utils.dart';
import '../html_text_viewer_control.dart';
import '../media_attachment_viewer_control.dart';
@ -49,6 +50,7 @@ class FlattenedTreeEntryControl extends StatefulWidget {
class _StatusControlState extends State<FlattenedTreeEntryControl> {
static final _logger = Logger('$FlattenedTreeEntryControl');
var showSpoilerControl = true;
var showContent = true;
var showFilteredPost = false;
var showComments = false;
@ -67,7 +69,8 @@ class _StatusControlState extends State<FlattenedTreeEntryControl> {
@override
void initState() {
super.initState();
showContent = entry.spoilerText.isEmpty;
showSpoilerControl = getIt<SettingsService>().spoilerHidingEnabled;
showContent = !showSpoilerControl ? true : entry.spoilerText.isEmpty;
showComments = isPost ? false : true;
}
@ -164,7 +167,7 @@ class _StatusControlState extends State<FlattenedTreeEntryControl> {
const VerticalPadding(
height: 5,
),
if (entry.spoilerText.isNotEmpty)
if (showSpoilerControl && entry.spoilerText.isNotEmpty)
TextButton(
onPressed: () {
setState(() {

View file

@ -38,8 +38,6 @@ class _PostControlState extends State<PostControl> {
final ItemPositionsListener itemPositionsListener =
ItemPositionsListener.create();
var showContent = true;
EntryTreeItem get item => widget.originalItem;
TimelineEntry get entry => item.entry;
@ -47,7 +45,6 @@ class _PostControlState extends State<PostControl> {
@override
void initState() {
super.initState();
showContent = entry.spoilerText.isEmpty;
}
@override

View file

@ -7,6 +7,7 @@ import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import '../../models/TimelineIdentifiers.dart';
import '../../services/network_status_service.dart';
import '../../services/setting_service.dart';
import '../../services/timeline_manager.dart';
import '../../utils/active_profile_selector.dart';
import 'post_control.dart';
@ -36,6 +37,7 @@ class TimelinePanel extends StatelessWidget {
@override
Widget build(BuildContext context) {
_logger.finer('Build');
context.watch<SettingsService>().spoilerHidingEnabled;
final nss = getIt<NetworkStatusService>();
final manager = context
.watch<ActiveProfileSelector<TimelineManager>>()

View file

@ -76,6 +76,16 @@ class OAuthCredentials implements ICredentials {
'id': id,
};
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is OAuthCredentials &&
runtimeType == other.runtimeType &&
id == other.id;
@override
int get hashCode => id.hashCode;
static OAuthCredentials fromJson(Map<String, dynamic> json) =>
OAuthCredentials(
clientId: json['clientId'],

View file

@ -32,6 +32,7 @@ class SettingsScreen extends StatelessWidget {
buildVersionString(),
buildLowBandwidthWidget(settings),
buildNotificationGroupingWidget(settings),
buildSpoilerHidingEnabledWidget(settings),
buildThemeWidget(settings),
if (!kReleaseMode) buildColorBlindnessTestSettings(settings),
buildClearCaches(context),
@ -80,6 +81,18 @@ class SettingsScreen extends StatelessWidget {
);
}
Widget buildSpoilerHidingEnabledWidget(SettingsService settings) {
return ListTile(
title: const Text('Spoiler/Content Warning Hiding'),
trailing: Switch(
onChanged: (value) {
settings.spoilerHidingEnabled = value;
},
value: settings.spoilerHidingEnabled,
),
);
}
Widget buildThemeWidget(SettingsService settings) {
return ListTile(
title: const Text('Dark Mode Theme:'),

View file

@ -34,6 +34,16 @@ class SettingsService extends ChangeNotifier {
notifyListeners();
}
var _spoilerHidingEnabled = true;
bool get spoilerHidingEnabled => _spoilerHidingEnabled;
set spoilerHidingEnabled(bool value) {
_spoilerHidingEnabled = value;
_prefs.setBool(_spoilerHidingEnabledKey, _spoilerHidingEnabled);
notifyListeners();
}
var _themeMode = ThemeMode.system;
ThemeMode get themeMode => _themeMode;
@ -83,6 +93,7 @@ class SettingsService extends ChangeNotifier {
_prefs = await SharedPreferences.getInstance();
_lowBandwidthMode = _prefs.getBool(_lowBandwidthModeKey) ?? false;
_notificationGrouping = _prefs.getBool(_notificationGroupingKey) ?? true;
_spoilerHidingEnabled = _prefs.getBool(_spoilerHidingEnabledKey) ?? true;
_themeMode = ThemeModeExtensions.parse(_prefs.getString(_themeModeKey));
_colorBlindnessType = _colorBlindnessTypeFromPrefs(_prefs);
_logLevel = _levelFromPrefs(_prefs);
@ -97,6 +108,7 @@ const _colorBlindnessTestingModeKey = 'ColorBlindnessTestingMode';
const _logLevelKey = 'LogLevel';
const _networkCapabilitiesKey = 'NetworkCapabilities';
const _notificationGroupingKey = 'NotificationGrouping';
const _spoilerHidingEnabledKey = 'SpoilerHidingEnabled';
ColorBlindnessType _colorBlindnessTypeFromPrefs(SharedPreferences prefs) {
final cbString = prefs.getString(_colorBlindnessTestingModeKey);