Skip to content

Commit

Permalink
Merge pull request #85 from shockbytes/22-add-timeline-feature
Browse files Browse the repository at this point in the history
22: add timeline feature
  • Loading branch information
shockbytes authored Nov 22, 2023
2 parents 4b6a56c + 8bf16da commit bc42c48
Show file tree
Hide file tree
Showing 16 changed files with 410 additions and 31 deletions.
1 change: 1 addition & 0 deletions assets/lottie/books-staple.json

Large diffs are not rendered by default.

13 changes: 10 additions & 3 deletions assets/translations/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,16 @@
"hint": "Title oder ISBN",
"title": "Titelsuche"
},
"reset": "TODO",
"reset_password": "TODO",
"reset_password_text": "TODO",
"timeline": {
"sorting": {
"started-in": "Gestartet in",
"ended-in": "Fertig in"
},
"empty": "Es sind noch keine Bücher in deiner Bibliothek vorhanden, um hier etwas anzuzeigen."
},
"reset": "Zurücksetzen",
"reset_password": "Password zurücksetzen",
"reset_password_text": "Wir versenden ein Email an deine registrierte Adresse, wo du weitere Instruktionen zum Zurücksetzen findest.",
"search": {
"empty": {
"action": "Online suchen",
Expand Down
7 changes: 7 additions & 0 deletions assets/translations/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@
"hint": "Title or ISBN",
"title": "Title search"
},
"timeline": {
"sorting": {
"started-in": "Started in",
"ended-in": "Finished in"
},
"empty": "There are no books in your library yet to build this view."
},
"reset": "Reset",
"reset_password": "Reset Password",
"reset_password_text": "A link will be sent to your registered email address with instructions on how to reset your password.",
Expand Down
4 changes: 4 additions & 0 deletions lib/src/data/settings/settings_repository.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:dantex/src/data/book/book_sort_strategy.dart';
import 'package:dantex/src/ui/timeline/timeline_sort.dart';
import 'package:flutter/material.dart';

abstract class SettingsRepository {
Expand All @@ -14,4 +15,7 @@ abstract class SettingsRepository {

void setIsRandomBooksEnabled({required bool isRandomBooksEnabled});
bool isRandomBooksEnabled();

void setTimelineSortStrategy(TimelineSortStrategy sort);
TimelineSortStrategy getTimelineSortStrategy();
}
16 changes: 16 additions & 0 deletions lib/src/data/settings/shared_preferences_settings_repository.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:dantex/src/data/book/book_sort_strategy.dart';
import 'package:dantex/src/data/settings/settings_repository.dart';
import 'package:dantex/src/ui/timeline/timeline_sort.dart';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'package:shared_preferences/shared_preferences.dart';
Expand All @@ -11,6 +12,7 @@ class SharedPreferencesSettingsRepository implements SettingsRepository {
static const _keyRandomBooksEnabled = 'key_random_books_enabled';
static const _keyThemeMode = 'key_theme_mode';
static const _keySortStrategy = 'key_sort_strategy';
static const _keyTimelineSortStrategy = 'key_timeline_sort_strategy';

final BehaviorSubject<ThemeMode> _themeModeSubject = BehaviorSubject();

Expand Down Expand Up @@ -73,4 +75,18 @@ class SharedPreferencesSettingsRepository implements SettingsRepository {
Stream<ThemeMode> observeThemeMode() {
return _themeModeSubject.stream;
}

@override
TimelineSortStrategy getTimelineSortStrategy() {
final int timelineSortStrategyOrdinal =
_sp.getInt(_keyTimelineSortStrategy) ?? 0;
return TimelineSortStrategy.values[timelineSortStrategyOrdinal];
}

@override
Future<void> setTimelineSortStrategy(
TimelineSortStrategy sortStrategy,
) async {
await _sp.setInt(_keyTimelineSortStrategy, sortStrategy.index);
}
}
78 changes: 78 additions & 0 deletions lib/src/data/timeline/timeline.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'package:collection/collection.dart';
import 'package:dantex/src/data/book/book_repository.dart';
import 'package:dantex/src/data/book/entity/book.dart';
import 'package:dantex/src/data/settings/settings_repository.dart';

import 'package:dantex/src/ui/timeline/timeline_sort.dart';
import 'package:rxdart/rxdart.dart';

class Timeline {
final SettingsRepository _settingsRepository;
final BookRepository _bookRepository;

final BehaviorSubject<TimelineSortStrategy> _sortStrategySubject;

Stream<TimelineSortStrategy> get sortStrategy => _sortStrategySubject.stream;

Timeline(this._settingsRepository, this._bookRepository)
: _sortStrategySubject = BehaviorSubject.seeded(
_settingsRepository.getTimelineSortStrategy(),
);

void setSortStrategy(TimelineSortStrategy sortStrategy) {
_sortStrategySubject.add(sortStrategy);
_settingsRepository.setTimelineSortStrategy(sortStrategy);
}

Stream<List<TimelineMonthGrouping>> getTimelineData() {
return _sortStrategySubject.flatMap(_createTimelineForSortStrategy);
}

Stream<List<TimelineMonthGrouping>> _createTimelineForSortStrategy(
TimelineSortStrategy sortStrategy,
) {
return _bookRepository.getAllBooks().map((books) {
return books
.where(
(element) {
return switch (sortStrategy) {
TimelineSortStrategy.byStartDate => element.startDate != null,
TimelineSortStrategy.byEndState => element.endDate != null,
};
},
)
.groupListsBy(
(e) {
return switch (_sortStrategySubject.value) {
TimelineSortStrategy.byStartDate => DateTime(
e.startDate!.year,
e.startDate!.month,
),
TimelineSortStrategy.byEndState => DateTime(
e.endDate!.year,
e.endDate!.month,
),
};
},
)
.entries
// Sort descending
.sorted((a, b) => a.key.isBefore(b.key) ? 1 : -1)
.map<TimelineMonthGrouping>(
(MapEntry<DateTime, List<Book>> entry) =>
TimelineMonthGrouping(month: entry.key, books: entry.value),
)
.toList();
});
}
}

class TimelineMonthGrouping {
final DateTime month;
final List<Book> books;

TimelineMonthGrouping({
required this.month,
required this.books,
});
}
9 changes: 9 additions & 0 deletions lib/src/providers/service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:dantex/src/data/isbn/isbn_scanner_service.dart';
import 'package:dantex/src/data/logging/error_only_filter.dart';
import 'package:dantex/src/data/logging/firebase_log_output.dart';
import 'package:dantex/src/data/search/search.dart';
import 'package:dantex/src/data/timeline/timeline.dart';
import 'package:dantex/src/providers/api.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
Expand Down Expand Up @@ -43,6 +44,14 @@ Search search(SearchRef ref) {
);
}

@riverpod
Timeline timeline(TimelineRef ref) {
return Timeline(
ref.read(settingsRepositoryProvider),
ref.read(bookRepositoryProvider),
);
}

@riverpod
SharedPreferences sharedPreferences(SharedPreferencesRef ref) =>
throw UnimplementedError();
Expand Down
24 changes: 24 additions & 0 deletions lib/src/ui/core/dante_components.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:flutter/services.dart';

class DanteDivider extends StatelessWidget {
final double width;

const DanteDivider({this.width = 0.5, super.key});

@override
Expand Down Expand Up @@ -111,6 +112,7 @@ class DanteTextField extends StatelessWidget {
class DanteOutlinedButton extends StatelessWidget {
final Widget child;
final void Function()? onPressed;

const DanteOutlinedButton({required this.child, super.key, this.onPressed});

@override
Expand All @@ -122,3 +124,25 @@ class DanteOutlinedButton extends StatelessWidget {
);
}
}

class DanteOutlinedCard extends StatelessWidget {
final Widget child;

const DanteOutlinedCard({required this.child, super.key});

@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.hardEdge,
elevation: 0,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Theme.of(context).colorScheme.outline,
width: 0.5,
),
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
child: child,
);
}
}
33 changes: 33 additions & 0 deletions lib/src/ui/core/lottie_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';

class LottieView extends StatelessWidget {
final String lottieAsset;
final String text;

const LottieView({
required this.lottieAsset,
required this.text,
super.key,
});

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LottieBuilder.asset(lottieAsset),
Text(
text,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
),
textAlign: TextAlign.center,
),
],
),
);
}
}
19 changes: 6 additions & 13 deletions lib/src/ui/core/themed_app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@ import 'package:flutter/material.dart';

class ThemedAppBar extends StatelessWidget implements PreferredSizeWidget {
final List<Widget>? actions;
final bool automaticallyImplyLeading;
final Widget? leading;
final Widget? title;
final ShapeBorder? border;
final Color? shadowColor;
final double elevation;

const ThemedAppBar({
super.key,
this.actions,
this.automaticallyImplyLeading = true,
this.leading,
this.title,
this.border,
this.shadowColor,
this.elevation = 0.0,
});

@override
Expand All @@ -27,14 +19,15 @@ class ThemedAppBar extends StatelessWidget implements PreferredSizeWidget {
Widget build(BuildContext context) {
return AppBar(
actions: actions,
automaticallyImplyLeading: automaticallyImplyLeading,
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
backgroundColor: Theme.of(context).colorScheme.background,
// Disable coloring of action bar on scroll
surfaceTintColor: Theme.of(context).colorScheme.background,
scrolledUnderElevation: 4,
shadowColor: Theme.of(context).colorScheme.onBackground,
centerTitle: true,
elevation: elevation,
elevation: 0,
leading: leading,
title: title,
shape: border,
shadowColor: shadowColor,
);
}
}
12 changes: 2 additions & 10 deletions lib/src/ui/settings/contributors_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:dantex/src/ui/core/dante_components.dart';
import 'package:dantex/src/util/url_launcher.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -90,16 +91,7 @@ class _ContributorCard extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.hardEdge,
elevation: 0,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Theme.of(context).colorScheme.outline,
width: 0.5,
),
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
return DanteOutlinedCard(
child: switch (_contribution) {
_Contributor() => _buildContributor(
context,
Expand Down
Loading

0 comments on commit bc42c48

Please sign in to comment.