Add Tags sidebar

Fixes #114

This was there because I couldn't figure out how to configure Billing in
iOS, now that it is done, I can have the pro mode in iOS as well.
This commit is contained in:
Vishesh Handa
2020-05-14 16:04:33 +02:00
parent 7ef9cfe60f
commit 5c04bf204e
8 changed files with 126 additions and 29 deletions

View File

@ -54,6 +54,8 @@ screens:
delete: Delete Folder
decoration: Folder Name
empty: Please enter a name
tags:
title: Tags
widgets:
rename:
yes: Rename

View File

@ -6,6 +6,7 @@ import 'package:firebase_analytics/observer.dart';
import 'package:flutter/material.dart';
import 'package:gitjournal/analytics.dart';
import 'package:gitjournal/screens/folder_listing.dart';
import 'package:gitjournal/screens/tag_listing.dart';
import 'package:gitjournal/screens/note_editor.dart';
import 'package:gitjournal/screens/purchase_screen.dart';
import 'package:gitjournal/screens/purchase_thankyou_screen.dart';
@ -293,7 +294,7 @@ class _JournalAppState extends State<JournalApp> {
//debugShowMaterialGrid: true,
onGenerateRoute: (settings) {
var route = settings.name;
if (route == '/folders') {
if (route == '/folders' || route == '/tags') {
return PageRouteBuilder(
settings: settings,
pageBuilder: (_, __, ___) => _screenForRoute(route, stateContainer),
@ -320,6 +321,8 @@ class _JournalAppState extends State<JournalApp> {
return HomeScreen();
case '/folders':
return FolderListingScreen();
case '/tags':
return TagListingScreen();
case '/settings':
return SettingsScreen();
case '/setupRemoteGit':

View File

@ -2,13 +2,17 @@ import 'package:gitjournal/core/note.dart';
import 'package:gitjournal/core/notes_folder.dart';
import 'package:gitjournal/core/notes_folder_notifier.dart';
typedef NotesFilter = bool Function(Note note);
class FlattenedNotesFolder with NotesFolderNotifier implements NotesFolder {
final NotesFolder _parentFolder;
final NotesFilter filter;
final String title;
var _notes = <Note>[];
var _folders = <NotesFolder>[];
FlattenedNotesFolder(this._parentFolder) {
FlattenedNotesFolder(this._parentFolder, {this.filter, this.title}) {
_addFolder(_parentFolder);
}
@ -57,11 +61,17 @@ class FlattenedNotesFolder with NotesFolderNotifier implements NotesFolder {
}
void _noteAdded(int _, Note note) {
if (filter != null && !filter(note)) {
return;
}
_notes.add(note);
notifyNoteAdded(-1, note);
}
void _noteRemoved(int _, Note note) {
if (filter != null && !filter(note)) {
return;
}
var i = _notes.indexWhere((n) => n.filePath == note.filePath);
assert(i != -1);
@ -70,7 +80,22 @@ class FlattenedNotesFolder with NotesFolderNotifier implements NotesFolder {
}
void _noteModified(int i, Note note) {
notifyNoteModified(-1, note);
if (filter == null) {
notifyNoteModified(-1, note);
return;
}
if (_notes.contains(note)) {
if (filter(note)) {
notifyNoteModified(-1, note);
} else {
_noteRemoved(-1, note);
}
} else {
if (filter(note)) {
_noteAdded(-1, note);
}
}
}
@override
@ -97,7 +122,7 @@ class FlattenedNotesFolder with NotesFolderNotifier implements NotesFolder {
}
@override
String get name => "All Notes";
String get name => title ?? "All Notes";
@override
NotesFolderConfig get config {

View File

@ -1,4 +1,3 @@
class Features {
static bool perFolderConfig = false;
static bool purchaseProModeAvailable = true;
}

View File

@ -5,7 +5,6 @@ import 'package:collection/collection.dart';
import 'package:gitjournal/core/note.dart';
import 'package:gitjournal/core/md_yaml_doc.dart';
import 'package:gitjournal/core/notes_folder.dart';
import 'package:gitjournal/core/notes_folder_fs.dart';
import 'package:gitjournal/editors/journal_editor.dart';
import 'package:gitjournal/editors/markdown_editor.dart';

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:gitjournal/features.dart';
import 'package:gitjournal/screens/settings_screen.dart';
import 'package:gitjournal/settings.dart';
import 'package:gitjournal/screens/settings_widgets.dart';
@ -48,25 +47,24 @@ class SettingsEditorsScreenState extends State<SettingsEditorsScreen> {
setState(() {});
},
),
if (Features.purchaseProModeAvailable) SettingsHeader("Journal Editor"),
if (Features.purchaseProModeAvailable)
ProSettingOverlay(
child: ListTile(
title: const Text("Default Folder"),
subtitle: Text(defaultNewFolder),
onTap: () async {
var destFolder = await showDialog<NotesFolderFS>(
context: context,
builder: (context) => FolderSelectionDialog(),
);
SettingsHeader("Journal Editor"),
ProSettingOverlay(
child: ListTile(
title: const Text("Default Folder"),
subtitle: Text(defaultNewFolder),
onTap: () async {
var destFolder = await showDialog<NotesFolderFS>(
context: context,
builder: (context) => FolderSelectionDialog(),
);
Settings.instance.journalEditordefaultNewNoteFolderSpec =
destFolder != null ? destFolder.pathSpec() : "";
Settings.instance.save();
setState(() {});
},
),
Settings.instance.journalEditordefaultNewNoteFolderSpec =
destFolder != null ? destFolder.pathSpec() : "";
Settings.instance.save();
setState(() {});
},
),
),
]);
return Scaffold(

View File

@ -0,0 +1,59 @@
import 'dart:collection';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:gitjournal/core/flattened_notes_folder.dart';
import 'package:gitjournal/core/note.dart';
import 'package:gitjournal/core/notes_folder_fs.dart';
import 'package:gitjournal/screens/folder_view.dart';
import 'package:gitjournal/widgets/app_bar_menu_button.dart';
import 'package:gitjournal/widgets/app_drawer.dart';
import 'package:provider/provider.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class TagListingScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
var rootFolder = Provider.of<NotesFolderFS>(context);
var allTags = rootFolder.getNoteTagsRecursively();
var allTagsSorted = SplayTreeSet<String>.from(allTags);
var listView = ListView(
children: <Widget>[
for (var tag in allTagsSorted) _buildTagTile(context, tag),
],
);
return Scaffold(
appBar: AppBar(
title: Text(tr('screens.tags.title')),
leading: GJAppBarMenuButton(),
),
body: Scrollbar(child: listView),
drawer: AppDrawer(),
);
}
Widget _buildTagTile(BuildContext context, String tag) {
var theme = Theme.of(context);
var titleColor = theme.textTheme.headline1.color;
return ListTile(
leading: FaIcon(FontAwesomeIcons.tag, color: titleColor),
title: Text(tag),
onTap: () {
var route = MaterialPageRoute(builder: (context) {
var rootFolder = Provider.of<NotesFolderFS>(context);
var folder = FlattenedNotesFolder(
rootFolder,
filter: (Note n) => n.tags.contains(tag),
title: tag,
);
return FolderView(notesFolder: folder);
});
Navigator.of(context).push(route);
},
);
}
}

View File

@ -2,7 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:gitjournal/features.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:gitjournal/settings.dart';
import 'package:gitjournal/utils/logger.dart';
import 'package:launch_review/launch_review.dart';
@ -65,7 +65,7 @@ class AppDrawer extends StatelessWidget {
),
),
if (setupGitButton != null) ...[setupGitButton, divider],
if (Features.purchaseProModeAvailable && !Settings.instance.proMode)
if (!Settings.instance.proMode)
_buildDrawerTile(
context,
icon: Icons.power,
@ -79,8 +79,7 @@ class AppDrawer extends StatelessWidget {
);
},
),
if (Features.purchaseProModeAvailable && !Settings.instance.proMode)
divider,
if (!Settings.instance.proMode) divider,
_buildDrawerTile(
context,
icon: Icons.note,
@ -95,6 +94,14 @@ class AppDrawer extends StatelessWidget {
onTap: () => _navTopLevel(context, '/folders'),
selected: currentRoute == "/folders",
),
_buildDrawerTile(
context,
icon: FontAwesomeIcons.tag,
isFontAwesome: true,
title: "Tags",
onTap: () => _navTopLevel(context, '/tags'),
selected: currentRoute == "/tags",
),
divider,
_buildDrawerTile(
context,
@ -205,6 +212,7 @@ class AppDrawer extends StatelessWidget {
@required IconData icon,
@required String title,
@required Function onTap,
bool isFontAwesome = false,
bool selected = false,
}) {
var theme = Theme.of(context);
@ -213,8 +221,12 @@ class AppDrawer extends StatelessWidget {
color: selected ? theme.accentColor : listTileTheme.textColor,
);
var iconW = !isFontAwesome
? Icon(icon, color: textStyle.color)
: FaIcon(icon, color: textStyle.color);
var tile = ListTile(
leading: Icon(icon, color: textStyle.color),
leading: iconW,
title: Text(title, style: textStyle),
onTap: onTap,
selected: selected,