diff --git a/lib/main_common.dart b/lib/main_common.dart
index 0dec2f1..1854e84 100644
--- a/lib/main_common.dart
+++ b/lib/main_common.dart
@@ -12,6 +12,7 @@ import 'l10n/timeago/pl.dart';
 import 'pages/log_console/log_console_page_store.dart';
 import 'stores/accounts_store.dart';
 import 'stores/config_store.dart';
+import 'stores/hidden_store.dart';
 import 'util/mobx_provider.dart';

 Future<void> mainCommon(AppConfig appConfig) async {
@@ -29,6 +30,7 @@ Future<void> mainCommon(AppConfig appConfig) async {
     MultiProvider(
       providers: [
         MobxProvider(create: (context) => ConfigStore.load(sharedPrefs)),
+        MobxProvider(create: (context) => HiddenStore.load(sharedPrefs)),
         ChangeNotifierProvider.value(value: accountsStore),
         MobxProvider.value(value: logConsoleStore),
       ],
diff --git a/lib/stores/hidden_store.dart b/lib/stores/hidden_store.dart
new file mode 100644
index 0000000..d00fe15
--- /dev/null
+++ b/lib/stores/hidden_store.dart
@@ -0,0 +1,50 @@
+import 'dart:convert';
+
+import 'package:flutter/material.dart';
+import 'package:json_annotation/json_annotation.dart';
+import 'package:mobx/mobx.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+import '../l10n/l10n.dart';
+import '../util/mobx_provider.dart';
+
+part 'hidden_store.g.dart';
+
+/// Store managing user-level configuration such as theme or language
+@JsonSerializable()
+@LocaleConverter()
+class HiddenStore extends _HiddenStore with _$HiddenStore, DisposableStore {
+  static const _prefsKey = 'v1:HiddenStore';
+  late final SharedPreferences _sharedPrefs;
+
+  @visibleForTesting
+  HiddenStore();
+
+  factory HiddenStore.load(SharedPreferences sharedPrefs) {
+    final store = _$HiddenStoreFromJson(
+      jsonDecode(sharedPrefs.getString(_prefsKey) ?? '{}')
+          as Map<String, dynamic>,
+    ).._sharedPrefs = sharedPrefs;
+
+    store.addReaction(autorun((_) => store.save()));
+
+    return store;
+  }
+
+  Future<void> save() async {
+    final serialized = jsonEncode(_$HiddenStoreToJson(this));
+
+    await _sharedPrefs.setString(_prefsKey, serialized);
+  }
+}
+
+abstract class _HiddenStore with Store {
+  @observable
+  @JsonKey(defaultValue: [])
+  List<int> postIds = [];
+
+  @action
+  void addPost(int postId) {
+    postIds.add(postId);
+  }
+}
diff --git a/lib/stores/hidden_store.g.dart b/lib/stores/hidden_store.g.dart
new file mode 100644
index 0000000..171e198
--- /dev/null
+++ b/lib/stores/hidden_store.g.dart
@@ -0,0 +1,61 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'hidden_store.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+HiddenStore _$HiddenStoreFromJson(Map<String, dynamic> json) => HiddenStore()
+  ..postIds =
+      (json['postIds'] as List<dynamic>?)?.map((e) => e as int).toList() ?? [];
+
+Map<String, dynamic> _$HiddenStoreToJson(HiddenStore instance) =>
+    <String, dynamic>{
+      'postIds': instance.postIds,
+    };
+
+// **************************************************************************
+// StoreGenerator
+// **************************************************************************
+
+// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers
+
+mixin _$HiddenStore on _HiddenStore, Store {
+  late final _$postIdsAtom =
+      Atom(name: '_HiddenStore.postIds', context: context);
+
+  @override
+  List<int> get postIds {
+    _$postIdsAtom.reportRead();
+    return super.postIds;
+  }
+
+  @override
+  set postIds(List<int> value) {
+    _$postIdsAtom.reportWrite(value, super.postIds, () {
+      super.postIds = value;
+    });
+  }
+
+  late final _$_HiddenStoreActionController =
+      ActionController(name: '_HiddenStore', context: context);
+
+  @override
+  void addPost(int postId) {
+    final _$actionInfo = _$_HiddenStoreActionController.startAction(
+        name: '_HiddenStore.addPost');
+    try {
+      return super.addPost(postId);
+    } finally {
+      _$_HiddenStoreActionController.endAction(_$actionInfo);
+    }
+  }
+
+  @override
+  String toString() {
+    return '''
+postIds: ${postIds}
+    ''';
+  }
+}
diff --git a/lib/widgets/post/post_actions.dart b/lib/widgets/post/post_actions.dart
index 1f89e1a..3764f6e 100644
--- a/lib/widgets/post/post_actions.dart
+++ b/lib/widgets/post/post_actions.dart
@@ -1,7 +1,9 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';

+import '../../hooks/stores.dart';
 import '../../l10n/l10n.dart';
+import '../../stores/hidden_store.dart';
 import '../../util/icons.dart';
 import '../../util/observer_consumers.dart';
 import '../../util/share.dart';
@@ -17,6 +19,7 @@ class PostActions extends HookWidget {
   Widget build(BuildContext context) {
     final fullPost = context.read<IsFullPost>();
     final shareButtonKey = GlobalKey();
+    final hiddenStore = useStore((HiddenStore store) => store);
     // assemble actions section
     return ObserverBuilder<PostStore>(builder: (context, store) {
       return Padding(
@@ -34,6 +37,16 @@ class PostActions extends HookWidget {
                 softWrap: false,
               ),
             ),
+            if (!fullPost)
+              IconButton(
+                onPressed: () =>
+                    // hiddenStore.postIds.add(store.postView.post.id),
+                    hiddenStore.postIds = [
+                  ...hiddenStore.postIds,
+                  store.postView.post.id
+                ],
+                icon: const Icon(Icons.visibility_off),
+              ),
             if (!fullPost)
               IconButton(
                 key: shareButtonKey,
diff --git a/lib/widgets/sortable_infinite_list.dart b/lib/widgets/sortable_infinite_list.dart
index 47a43ae..be0e73a 100644
--- a/lib/widgets/sortable_infinite_list.dart
+++ b/lib/widgets/sortable_infinite_list.dart
@@ -7,6 +7,7 @@ import '../hooks/infinite_scroll.dart';
 import '../hooks/stores.dart';
 import '../resources/app_theme.dart';
 import '../stores/config_store.dart';
+import '../stores/hidden_store.dart';
 import '../util/observer_consumers.dart';
 import 'comment/comment.dart';
 import 'comment_list_options.dart';
@@ -128,32 +129,42 @@ class InfinitePostList extends SortableInfiniteList<PostView> {
     required super.fetcher,
     super.controller,
   }) : super(
-          itemBuilder: (post) => Consumer<AppTheme>(
-              builder: (context, state, child) => Column(
-                    children: [
-                      PostTile.fromPostView(post),
-                      if (state.amoled)
-                        SizedBox(
-                          width: 250,
-                          height: 1,
-                          child: Container(
-                            decoration: BoxDecoration(
-                                gradient: LinearGradient(
-                              begin: Alignment.topRight,
-                              end: Alignment.bottomLeft,
-                              colors: [
-                                Theme.of(context).primaryColorDark,
-                                Theme.of(context).colorScheme.secondary,
-                                Theme.of(context).primaryColorDark,
-                              ],
-                            )),
+          itemBuilder: (post) => ObserverBuilder<HiddenStore>(
+              builder: (context, hiddenStore) => AnimatedCrossFade(
+                    duration: const Duration(milliseconds: 300),
+                    firstChild: const SizedBox(height: 0),
+                    secondChild: Consumer<AppTheme>(
+                      builder: (context, state, child) => Column(
+                        children: [
+                          PostTile.fromPostView(post),
+                          if (state.amoled)
+                            SizedBox(
+                              width: 250,
+                              height: 1,
+                              child: Container(
+                                decoration: BoxDecoration(
+                                    gradient: LinearGradient(
+                                  begin: Alignment.topRight,
+                                  end: Alignment.bottomLeft,
+                                  colors: [
+                                    Theme.of(context).primaryColorDark,
+                                    Theme.of(context).colorScheme.secondary,
+                                    Theme.of(context).primaryColorDark,
+                                  ],
+                                )),
+                              ),
+                            ),
+                          SizedBox(
+                            height: context.read<ConfigStore>().compactPostView
+                                ? 2
+                                : 10,
                           ),
-                        ),
-                      SizedBox(
-                          height: context.read<ConfigStore>().compactPostView
-                              ? 2
-                              : 10),
-                    ],
+                        ],
+                      ),
+                    ),
+                    crossFadeState: hiddenStore.postIds.contains(post.post.id)
+                        ? CrossFadeState.showFirst
+                        : CrossFadeState.showSecond,
                   )),
           noItems: const Text('there are no posts'),
           uniqueProp: (item) => item.post.apId,
Edit
Pub: 03 Jul 2023 23:42 UTC
Views: 97