Skip to content

Commit

Permalink
v.1.7.0 (#188)
Browse files Browse the repository at this point in the history
* easy sorting picker for preview collections

* tweaks

* doujin filter

* home nav bar profile icon now also opens settings

* update versioning

---------

Co-authored-by: lotus <[email protected]>
  • Loading branch information
lotusprey and lotus committed Jan 18, 2025
1 parent 8b19a54 commit 4cdc215
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 109 deletions.
3 changes: 3 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/83.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- In the collection filter sheets for both your anime and manga collection, you can explicitly set the preview collection sorting, separately from the one for the full collection. The exclusive airing sorting for anime collection preview toggle is removed from settings.
- Added a doujin filter in the discover filter sheet.
- While on the profile tab of the home screen, tapping the profile icon will scroll to top like before. But now it will also open settings, if you're already at the top.
4 changes: 3 additions & 1 deletion lib/feature/collection/collection_entries_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ final collectionEntriesProvider =
final mediaFilter = filter.mediaFilter;
final search = filter.search.toLowerCase();

ref.watch(collectionProvider(tag).notifier).ensureSorted(mediaFilter.sort);
ref
.watch(collectionProvider(tag).notifier)
.ensureSorted(mediaFilter.sort, mediaFilter.previewSort);

final entries = ref
.watch(collectionProvider(tag))
Expand Down
19 changes: 15 additions & 4 deletions lib/feature/collection/collection_filter_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@ class CollectionFilter {
}

class CollectionMediaFilter {
CollectionMediaFilter(this.sort);
CollectionMediaFilter()
: sort = EntrySort.title,
previewSort = EntrySort.title;

factory CollectionMediaFilter.fromPersistenceMap(Map<dynamic, dynamic> map) {
factory CollectionMediaFilter.fromPersistenceMap(
Map<dynamic, dynamic> map,
) {
final sort = EntrySort.values.getOrFirst(map['sort']);
final previewSort = EntrySort.values.getOrFirst(map['previewSort']);

final filter = CollectionMediaFilter(sort)
final filter = CollectionMediaFilter()
..sort = sort
..previewSort = previewSort
..startYearFrom = map['startYearFrom']
..startYearTo = map['startYearTo']
..country = OriginCountry.values.getOrNull(map['country'])
Expand Down Expand Up @@ -61,6 +68,7 @@ class CollectionMediaFilter {
final tagIn = <String>[];
final tagNotIn = <String>[];
EntrySort sort;
EntrySort previewSort;
int? startYearFrom;
int? startYearTo;
OriginCountry? country;
Expand All @@ -80,7 +88,9 @@ class CollectionMediaFilter {
isPrivate != null ||
hasNotes != null;

CollectionMediaFilter copy() => CollectionMediaFilter(sort)
CollectionMediaFilter copy() => CollectionMediaFilter()
..sort = sort
..previewSort = previewSort
..statuses.addAll(statuses)
..formats.addAll(formats)
..genreIn.addAll(genreIn)
Expand All @@ -101,6 +111,7 @@ class CollectionMediaFilter {
'tagIn': tagIn,
'tagNotIn': tagNotIn,
'sort': sort.index,
'previewSort': previewSort.index,
'startYearFrom': startYearFrom,
'startYearTo': startYearTo,
'country': country?.index,
Expand Down
28 changes: 6 additions & 22 deletions lib/feature/collection/collection_filter_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:otraku/feature/collection/collection_filter_model.dart';
import 'package:otraku/feature/viewer/persistence_provider.dart';
import 'package:otraku/feature/collection/collection_models.dart';
import 'package:otraku/feature/home/home_provider.dart';
import 'package:otraku/feature/media/media_models.dart';

final collectionFilterProvider = NotifierProvider.autoDispose
.family<CollectionFilterNotifier, CollectionFilter, CollectionTag>(
Expand All @@ -14,27 +12,13 @@ class CollectionFilterNotifier
extends AutoDisposeFamilyNotifier<CollectionFilter, CollectionTag> {
@override
CollectionFilter build(arg) {
final mediaFilter = arg.ofAnime
? ref.watch(
persistenceProvider.select((s) => s.animeCollectionMediaFilter),
)
: ref.watch(
persistenceProvider.select((s) => s.mangaCollectionMediaFilter),
);
final mediaFilter = ref.watch(persistenceProvider.select(
(s) => arg.ofAnime
? s.animeCollectionMediaFilter
: s.mangaCollectionMediaFilter,
));

final options = ref.watch(persistenceProvider.select((s) => s.options));
final isInAnimePreviewProvider = homeProvider.select(
(s) => !s.didExpandAnimeCollection,
);

if (arg.userId == ref.watch(viewerIdProvider) &&
arg.ofAnime &&
options.airingSortForAnimePreview &&
ref.watch(isInAnimePreviewProvider)) {
mediaFilter.sort = EntrySort.airing;
}

return CollectionFilter(mediaFilter);
return CollectionFilter(mediaFilter.copy());
}

CollectionFilter update(
Expand Down
22 changes: 12 additions & 10 deletions lib/feature/collection/collection_filter_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ class _FilterCollectionViewState extends ConsumerState<CollectionFilterView> {
),
);

Widget? previewSortPicker;
if (ofViewer &&
(widget.tag.ofAnime && options.animeCollectionPreview ||
!widget.tag.ofAnime && options.mangaCollectionPreview)) {
previewSortPicker = EntrySortChipSelector(
title: 'Preview Sorting',
value: _filter.previewSort,
onChanged: (v) => _filter.previewSort = v,
);
}

return SheetWithButtonRow(
buttons: BottomBar(
options.leftHanded
Expand All @@ -104,16 +115,7 @@ class _FilterCollectionViewState extends ConsumerState<CollectionFilterView> {
value: _filter.sort,
onChanged: (v) => _filter.sort = v,
),
if (ofViewer &&
_filter.sort == EntrySort.airing &&
options.airingSortForAnimePreview)
Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Text(
'Note: Airing sort is set to replace your default one for the anime preview. You can turn it off in the settings.',
style: TextTheme.of(context).labelMedium,
),
),
if (previewSortPicker != null) previewSortPicker,
ChipMultiSelector(
title: 'Statuses',
items: ReleaseStatus.values.map((v) => (v.label, v)).toList(),
Expand Down
6 changes: 1 addition & 5 deletions lib/feature/collection/collection_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,7 @@ class _Tile extends StatelessWidget {
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(
top: Theming.offset,
left: Theming.offset,
right: Theming.offset,
),
padding: Theming.paddingAll,
child: _TileContent(entry, scoreFormat, onProgressUpdated),
),
),
Expand Down
15 changes: 10 additions & 5 deletions lib/feature/collection/collection_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,17 @@ class CollectionNotifier
return collection;
}

void ensureSorted(EntrySort sort) {
if (_sort == sort) return;
_sort = sort;

void ensureSorted(EntrySort sort, EntrySort previewSort) {
_updateState((collection) {
collection.sort(sort);
final selectedSort = switch (collection) {
FullCollection _ => sort,
PreviewCollection _ => previewSort,
};

if (_sort == selectedSort) return;
_sort = selectedSort;

collection.sort(selectedSort);
return null;
});
}
Expand Down
12 changes: 9 additions & 3 deletions lib/feature/discover/discover_filter_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class DiscoverMediaFilter {
..startYearTo = map['startYearTo']
..country = OriginCountry.values.getOrNull(map['country'])
..inLists = map['inLists']
..isAdult = map['isAdult'];
..isAdult = map['isAdult']
..isLicensed = map['isLicensed'];

for (final e in map['statuses'] ?? const []) {
final status = ReleaseStatus.values.getOrNull(e);
Expand Down Expand Up @@ -105,6 +106,7 @@ class DiscoverMediaFilter {
OriginCountry? country;
bool? inLists;
bool? isAdult;
bool? isLicensed;

bool get isActive =>
statuses.isNotEmpty ||
Expand All @@ -120,7 +122,8 @@ class DiscoverMediaFilter {
startYearTo != null ||
country != null ||
inLists != null ||
isAdult != null;
isAdult != null ||
isLicensed != null;

DiscoverMediaFilter copy() => DiscoverMediaFilter(sort)
..statuses.addAll(statuses)
Expand All @@ -136,7 +139,8 @@ class DiscoverMediaFilter {
..startYearTo = startYearTo
..country = country
..inLists = inLists
..isAdult = isAdult;
..isAdult = isAdult
..isLicensed = isLicensed;

static DiscoverMediaFilter fromCollection({
required CollectionMediaFilter filter,
Expand Down Expand Up @@ -174,6 +178,7 @@ class DiscoverMediaFilter {
if (country != null) 'countryOfOrigin': country!.code,
if (inLists != null) 'onList': inLists,
if (isAdult != null) 'isAdult': isAdult,
if (isLicensed != null) 'isLicensed': isLicensed,
};

Map<String, dynamic> toPersistenceMap() => {
Expand All @@ -192,5 +197,6 @@ class DiscoverMediaFilter {
'country': country?.index,
'inLists': inLists,
'isAdult': isAdult,
'isLicensed': isLicensed,
};
}
6 changes: 6 additions & 0 deletions lib/feature/discover/discover_filter_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ class _DiscoverFilterViewState extends ConsumerState<DiscoverFilterView> {
value: _filter.isAdult,
onChanged: (v) => _filter.isAdult = v,
),
ChipSelector(
title: 'Licensing',
items: const [('Licensed', true), ('Doujin', false)],
value: _filter.isLicensed,
onChanged: (v) => _filter.isLicensed = v,
),
SizedBox(
height: MediaQuery.paddingOf(context).bottom +
BottomBar.height +
Expand Down
29 changes: 17 additions & 12 deletions lib/feature/home/home_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -174,32 +174,37 @@ class _HomeViewState extends ConsumerState<HomeView>
final tab = HomeTab.values[i];

switch (tab) {
case HomeTab.feed:
_feedScrollCtrl.scrollToTop();
case HomeTab.anime:
if (_animeScrollCtrl.position.pixels > 0) {
_animeScrollCtrl.scrollToTop();
} else {
_toggleSearchFocus();
return;
}
return;

_toggleSearchFocus();
case HomeTab.manga:
if (_mangaScrollCtrl.position.pixels > 0) {
_mangaScrollCtrl.scrollToTop();
} else {
_toggleSearchFocus();
return;
}
return;

_toggleSearchFocus();
case HomeTab.discover:
if (_discoverScrollCtrl.position.pixels > 0) {
_discoverScrollCtrl.scrollToTop();
} else {
_toggleSearchFocus();
return;
}

_toggleSearchFocus();
return;
case HomeTab.feed:
_feedScrollCtrl.scrollToTop();
case HomeTab.profile:
primaryScrollCtrl.scrollToTop();
return;
if (primaryScrollCtrl.positions.last.pixels > 0) {
primaryScrollCtrl.scrollToTop();
return;
}

context.push(Routes.settings);
}
},
);
Expand Down
14 changes: 2 additions & 12 deletions lib/feature/settings/settings_app_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class SettingsAppSubview extends ConsumerWidget {
controller: scrollCtrl,
padding: EdgeInsets.only(
top: listPadding.top + Theming.offset,
bottom: listPadding.bottom + Theming.offset,
bottom: listPadding.bottom + Theming.offset + 60,
),
children: [
ExpansionTile(
Expand All @@ -50,6 +50,7 @@ class SettingsAppSubview extends ConsumerWidget {
ThemePreview(ref: ref, options: options),
StatefulSwitchListTile(
title: const Text('High Contrast'),
subtitle: const Text('Pure white/black backgrounds'),
value: options.highContrast,
onChanged: (v) => update(options.copyWith(highContrast: v)),
),
Expand Down Expand Up @@ -80,17 +81,6 @@ class SettingsAppSubview extends ConsumerWidget {
options.copyWith(mangaCollectionPreview: v),
),
),
StatefulSwitchListTile(
title: const Text('Force Airing Sort for Anime Preview'),
subtitle: const Text(
'Sort by soonest airing, instead of the default',
),
value: options.airingSortForAnimePreview,
onChanged: (v) => update(
options.copyWith(airingSortForAnimePreview: v),
),
),
const SizedBox(height: 5),
],
),
ExpansionTile(
Expand Down
Loading

0 comments on commit 4cdc215

Please sign in to comment.