mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-07-21 07:03:25 +08:00
Add a sync button to the AppBar
This somewhat shows what's going on with the network. It isn't ideal, as is a bit ugly. But it's a start to show the network status, and what's going on in the background.
This commit is contained in:
@ -1,7 +1,15 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:fimber/fimber.dart';
|
||||
|
||||
import 'package:gitjournal/core/notes_folder.dart';
|
||||
|
||||
enum SyncStatus {
|
||||
Unknown,
|
||||
Done,
|
||||
Loading,
|
||||
Error,
|
||||
}
|
||||
|
||||
class AppState {
|
||||
//
|
||||
// Saved on Disk
|
||||
@ -15,6 +23,8 @@ class AppState {
|
||||
|
||||
bool onBoardingCompleted = false;
|
||||
|
||||
SyncStatus syncStatus = SyncStatus.Unknown;
|
||||
|
||||
//
|
||||
// Temporary
|
||||
//
|
||||
|
@ -102,7 +102,7 @@ class GitNoteRepository {
|
||||
return _addNote(note, "Edited Note");
|
||||
}
|
||||
|
||||
Future<bool> sync() async {
|
||||
Future<void> sync() async {
|
||||
try {
|
||||
await _gitRepo.pull();
|
||||
} on GitException catch (e, stacktrace) {
|
||||
@ -120,8 +120,6 @@ class GitNoteRepository {
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:git_bindings/git_bindings.dart';
|
||||
import 'package:gitjournal/appstate.dart';
|
||||
|
||||
import 'package:gitjournal/core/note.dart';
|
||||
import 'package:gitjournal/core/notes_folder.dart';
|
||||
import 'package:gitjournal/utils.dart';
|
||||
import 'package:git_bindings/git_bindings.dart';
|
||||
import 'package:gitjournal/screens/journal_editor.dart';
|
||||
import 'package:gitjournal/screens/journal_browsing.dart';
|
||||
import 'package:gitjournal/state_container.dart';
|
||||
@ -19,6 +21,7 @@ class JournalListingScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final container = StateContainer.of(context);
|
||||
final appState = container.appState;
|
||||
|
||||
var createButton = FloatingActionButton(
|
||||
key: const ValueKey("FAB"),
|
||||
@ -50,6 +53,7 @@ class JournalListingScreen extends StatelessWidget {
|
||||
title: Text(title),
|
||||
leading: GJAppBarMenuButton(),
|
||||
actions: <Widget>[
|
||||
if (appState.remoteGitRepoConfigured) SyncButton(),
|
||||
IconButton(
|
||||
icon: Icon(Icons.search),
|
||||
onPressed: () {
|
||||
@ -58,25 +62,29 @@ class JournalListingScreen extends StatelessWidget {
|
||||
delegate: NoteSearch(allNotes),
|
||||
);
|
||||
},
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: createButton,
|
||||
body: Center(
|
||||
child: RefreshIndicator(
|
||||
child: Scrollbar(child: journalList),
|
||||
onRefresh: () async {
|
||||
try {
|
||||
await container.syncNotes();
|
||||
} on GitException catch (exp) {
|
||||
showSnackbar(context, exp.cause);
|
||||
}
|
||||
}),
|
||||
child: Scrollbar(child: journalList),
|
||||
onRefresh: () async => _syncRepo(context),
|
||||
),
|
||||
),
|
||||
drawer: AppDrawer(),
|
||||
);
|
||||
}
|
||||
|
||||
void _syncRepo(BuildContext context) async {
|
||||
final container = StateContainer.of(context);
|
||||
try {
|
||||
await container.syncNotes();
|
||||
} on GitException catch (exp) {
|
||||
showSnackbar(context, exp.cause);
|
||||
}
|
||||
}
|
||||
|
||||
void _newPost(BuildContext context) {
|
||||
var route = MaterialPageRoute(
|
||||
builder: (context) => JournalEditor.newNote(notesFolder));
|
||||
@ -157,3 +165,95 @@ class NoteSearch extends SearchDelegate<Note> {
|
||||
return journalList;
|
||||
}
|
||||
}
|
||||
|
||||
class SyncButton extends StatefulWidget {
|
||||
@override
|
||||
_SyncButtonState createState() => _SyncButtonState();
|
||||
}
|
||||
|
||||
class _SyncButtonState extends State<SyncButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final container = StateContainer.of(context);
|
||||
final appState = container.appState;
|
||||
|
||||
if (appState.syncStatus == SyncStatus.Loading) {
|
||||
return RotatingIcon();
|
||||
}
|
||||
return IconButton(
|
||||
icon: Icon(_syncStatusIcon()),
|
||||
onPressed: () async {
|
||||
_syncRepo();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _syncRepo() async {
|
||||
final container = StateContainer.of(context);
|
||||
try {
|
||||
await container.syncNotes();
|
||||
} on GitException catch (exp) {
|
||||
showSnackbar(context, exp.cause);
|
||||
}
|
||||
}
|
||||
|
||||
IconData _syncStatusIcon() {
|
||||
final container = StateContainer.of(context);
|
||||
final appState = container.appState;
|
||||
switch (appState.syncStatus) {
|
||||
case SyncStatus.Error:
|
||||
return Icons.cloud_off;
|
||||
|
||||
case SyncStatus.Unknown:
|
||||
case SyncStatus.Done:
|
||||
default:
|
||||
return Icons.cloud_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RotatingIcon extends StatefulWidget {
|
||||
@override
|
||||
_RotatingIconState createState() => _RotatingIconState();
|
||||
}
|
||||
|
||||
class _RotatingIconState extends State<RotatingIcon>
|
||||
with SingleTickerProviderStateMixin {
|
||||
AnimationController _controller;
|
||||
Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 1800),
|
||||
);
|
||||
_animation = CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.linear,
|
||||
);
|
||||
|
||||
_controller.repeat(reverse: true);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var button = IconButton(
|
||||
icon: const Icon(Icons.loop),
|
||||
onPressed: () {},
|
||||
);
|
||||
|
||||
return RotationTransition(
|
||||
child: button,
|
||||
turns: _animation,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -85,16 +85,31 @@ class StateContainerState extends State<StateContainer> {
|
||||
await appState.notesFolder.loadRecursively();
|
||||
}
|
||||
|
||||
Future syncNotes() async {
|
||||
Future<void> syncNotes() async {
|
||||
if (!appState.remoteGitRepoConfigured) {
|
||||
Fimber.d("Not syncing because RemoteRepo not configured");
|
||||
return true;
|
||||
}
|
||||
|
||||
await _gitRepo.sync();
|
||||
await _loadNotes();
|
||||
setState(() {
|
||||
appState.syncStatus = SyncStatus.Loading;
|
||||
});
|
||||
|
||||
return true;
|
||||
try {
|
||||
await _gitRepo.sync();
|
||||
|
||||
setState(() {
|
||||
Fimber.d("Synced!");
|
||||
appState.syncStatus = SyncStatus.Done;
|
||||
});
|
||||
} catch (Exeception) {
|
||||
setState(() {
|
||||
Fimber.d("Failed to Sync");
|
||||
appState.syncStatus = SyncStatus.Error;
|
||||
});
|
||||
rethrow;
|
||||
}
|
||||
await _loadNotes();
|
||||
}
|
||||
|
||||
void createFolder(NotesFolder parent, String folderName) async {
|
||||
|
Reference in New Issue
Block a user