mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-29 02:07:39 +08:00
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:
@ -54,6 +54,8 @@ screens:
|
||||
delete: Delete Folder
|
||||
decoration: Folder Name
|
||||
empty: Please enter a name
|
||||
tags:
|
||||
title: Tags
|
||||
widgets:
|
||||
rename:
|
||||
yes: Rename
|
||||
|
@ -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':
|
||||
|
@ -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 {
|
||||
|
@ -1,4 +1,3 @@
|
||||
class Features {
|
||||
static bool perFolderConfig = false;
|
||||
static bool purchaseProModeAvailable = true;
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -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(
|
||||
|
59
lib/screens/tag_listing.dart
Normal file
59
lib/screens/tag_listing.dart
Normal 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);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
Reference in New Issue
Block a user