Compare commits
8 Commits
16589be409
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 9261ec341e | |||
| 7ec7b20e74 | |||
| 829bf7512a | |||
| 4fe8896f9e | |||
| d3addc7973 | |||
| f1b1ccf6be | |||
| 99300478d5 | |||
| f6585e9850 |
@@ -11,12 +11,12 @@ android {
|
|||||||
ndkVersion = "27.2.12479018"
|
ndkVersion = "27.2.12479018"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
subprojects {
|
||||||
|
afterEvaluate {
|
||||||
|
val android = project.extensions.findByName("android")
|
||||||
|
if (android is com.android.build.gradle.BaseExtension) {
|
||||||
|
// Force the same sdk version everywhere
|
||||||
|
android.ndkVersion = "27.2.12479018"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
@@ -19,3 +29,4 @@ subprojects {
|
|||||||
tasks.register<Delete>("clean") {
|
tasks.register<Delete>("clean") {
|
||||||
delete(rootProject.layout.buildDirectory)
|
delete(rootProject.layout.buildDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
id("com.android.application") version "8.7.3" apply false
|
id("com.android.application") version "8.9.1" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,16 @@ class SyncResult {
|
|||||||
final bool isOnline;
|
final bool isOnline;
|
||||||
final int changesSynced;
|
final int changesSynced;
|
||||||
final int annotationsSynced;
|
final int annotationsSynced;
|
||||||
|
final int changesUnsynced;
|
||||||
|
final int annotationsUnsynced;
|
||||||
|
|
||||||
SyncResult({
|
SyncResult({
|
||||||
required this.sheets,
|
required this.sheets,
|
||||||
required this.isOnline,
|
required this.isOnline,
|
||||||
this.changesSynced = 0,
|
required this.changesSynced,
|
||||||
this.annotationsSynced = 0,
|
required this.annotationsSynced,
|
||||||
|
required this.changesUnsynced,
|
||||||
|
required this.annotationsUnsynced,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +84,8 @@ class SyncService {
|
|||||||
|
|
||||||
// 3. Upload pending annotations
|
// 3. Upload pending annotations
|
||||||
annotationsSynced = await _uploadPendingAnnotations();
|
annotationsSynced = await _uploadPendingAnnotations();
|
||||||
|
final remainingAnnotations = await _storageService
|
||||||
|
.readPendingAnnotationUploads();
|
||||||
|
|
||||||
// 4. Apply any remaining local changes (in case some failed to upload)
|
// 4. Apply any remaining local changes (in case some failed to upload)
|
||||||
final changeQueue = await _storageService.readChangeQueue();
|
final changeQueue = await _storageService.readChangeQueue();
|
||||||
@@ -102,6 +108,8 @@ class SyncService {
|
|||||||
isOnline: true,
|
isOnline: true,
|
||||||
changesSynced: changesSynced,
|
changesSynced: changesSynced,
|
||||||
annotationsSynced: annotationsSynced,
|
annotationsSynced: annotationsSynced,
|
||||||
|
changesUnsynced: changeQueue.length,
|
||||||
|
annotationsUnsynced: remainingAnnotations.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,9 +135,16 @@ class SyncService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final remainingAnnotations = await _storageService
|
||||||
|
.readPendingAnnotationUploads();
|
||||||
|
|
||||||
return SyncResult(
|
return SyncResult(
|
||||||
sheets: sheets,
|
sheets: sheets,
|
||||||
isOnline: false,
|
isOnline: false,
|
||||||
|
changesSynced: 0,
|
||||||
|
annotationsSynced: 0,
|
||||||
|
changesUnsynced: changeQueue.length,
|
||||||
|
annotationsUnsynced: remainingAnnotations.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ class _HomePageState extends State<HomePage> with RouteAware {
|
|||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// Exit fullscreen when entering home page
|
// Exit fullscreen when entering home page
|
||||||
|
if (FullScreen.isFullScreen) {
|
||||||
FullScreen.setFullScreen(false);
|
FullScreen.setFullScreen(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Subscribe to route changes
|
// Subscribe to route changes
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
@@ -71,14 +73,19 @@ class _HomePageState extends State<HomePage> with RouteAware {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void didPush() {
|
void didPush() {
|
||||||
|
// Exit fullscreen when entering home page
|
||||||
|
if (FullScreen.isFullScreen) {
|
||||||
FullScreen.setFullScreen(false);
|
FullScreen.setFullScreen(false);
|
||||||
|
}
|
||||||
super.didPush();
|
super.didPush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didPopNext() {
|
void didPopNext() {
|
||||||
// Exit fullscreen when returning to home page
|
// Exit fullscreen when returning to home page
|
||||||
|
if (FullScreen.isFullScreen) {
|
||||||
FullScreen.setFullScreen(false);
|
FullScreen.setFullScreen(false);
|
||||||
|
}
|
||||||
super.didPopNext();
|
super.didPopNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +219,7 @@ class _HomePageState extends State<HomePage> with RouteAware {
|
|||||||
onLogout: _handleLogout,
|
onLogout: _handleLogout,
|
||||||
appName: _appName,
|
appName: _appName,
|
||||||
appVersion: _appVersion,
|
appVersion: _appVersion,
|
||||||
|
syncFuture: _syncFuture,
|
||||||
),
|
),
|
||||||
body: RefreshIndicator(onRefresh: _refreshSheets, child: _buildBody()),
|
body: RefreshIndicator(onRefresh: _refreshSheets, child: _buildBody()),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:sheetless/core/services/sync_service.dart';
|
||||||
|
|
||||||
/// Callback for shuffle state changes.
|
/// Callback for shuffle state changes.
|
||||||
typedef ShuffleCallback = void Function(bool enabled);
|
typedef ShuffleCallback = void Function(bool enabled);
|
||||||
@@ -12,12 +13,14 @@ class AppDrawer extends StatelessWidget {
|
|||||||
final VoidCallback onLogout;
|
final VoidCallback onLogout;
|
||||||
final String? appName;
|
final String? appName;
|
||||||
final String? appVersion;
|
final String? appVersion;
|
||||||
|
final Future<SyncResult> syncFuture;
|
||||||
|
|
||||||
const AppDrawer({
|
const AppDrawer({
|
||||||
super.key,
|
super.key,
|
||||||
required this.isShuffling,
|
required this.isShuffling,
|
||||||
required this.onShuffleChanged,
|
required this.onShuffleChanged,
|
||||||
required this.onLogout,
|
required this.onLogout,
|
||||||
|
required this.syncFuture,
|
||||||
this.appName,
|
this.appName,
|
||||||
this.appVersion,
|
this.appVersion,
|
||||||
});
|
});
|
||||||
@@ -32,7 +35,7 @@ class AppDrawer extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
_buildActions(),
|
_buildActions(),
|
||||||
_buildAppInfo(),
|
Column(children: [_buildSyncStatus(), _buildAppInfo()]),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -44,10 +47,7 @@ class AppDrawer extends StatelessWidget {
|
|||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(
|
leading: Icon(Icons.shuffle, color: isShuffling ? Colors.blue : null),
|
||||||
Icons.shuffle,
|
|
||||||
color: isShuffling ? Colors.blue : null,
|
|
||||||
),
|
|
||||||
title: const Text('Shuffle'),
|
title: const Text('Shuffle'),
|
||||||
onTap: () => onShuffleChanged(!isShuffling),
|
onTap: () => onShuffleChanged(!isShuffling),
|
||||||
),
|
),
|
||||||
@@ -60,6 +60,47 @@ class AppDrawer extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildSyncStatus() {
|
||||||
|
return Center(
|
||||||
|
// padding: const EdgeInsets.all(5.0),
|
||||||
|
child: FutureBuilder<SyncResult>(
|
||||||
|
future: syncFuture,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshot.hasError) {
|
||||||
|
return Text(
|
||||||
|
"Error: ${snapshot.error.toString()}",
|
||||||
|
style: const TextStyle(color: Colors.red),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
final changes = snapshot.data!.changesUnsynced;
|
||||||
|
final annotations = snapshot.data!.annotationsUnsynced;
|
||||||
|
if (changes == 0 && annotations == 0) {
|
||||||
|
return Text(
|
||||||
|
"All synced!",
|
||||||
|
style: const TextStyle(color: Colors.black),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Text(
|
||||||
|
"$changes changes and $annotations annotations unsynchronized!",
|
||||||
|
style: const TextStyle(color: Colors.red),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildAppInfo() {
|
Widget _buildAppInfo() {
|
||||||
final versionText = appName != null && appVersion != null
|
final versionText = appName != null && appVersion != null
|
||||||
? '$appName v$appVersion'
|
? '$appName v$appVersion'
|
||||||
@@ -67,10 +108,7 @@ class AppDrawer extends StatelessWidget {
|
|||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Text(
|
child: Text(versionText, style: const TextStyle(color: Colors.grey)),
|
||||||
versionText,
|
|
||||||
style: const TextStyle(color: Colors.grey),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,9 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
_rightDrawingController = DrawingController(maxHistorySteps: 50);
|
_rightDrawingController = DrawingController(maxHistorySteps: 50);
|
||||||
|
|
||||||
FullScreen.addListener(this);
|
FullScreen.addListener(this);
|
||||||
|
if (FullScreen.isFullScreen != widget.config.fullscreen) {
|
||||||
FullScreen.setFullScreen(widget.config.fullscreen);
|
FullScreen.setFullScreen(widget.config.fullscreen);
|
||||||
|
}
|
||||||
_documentLoaded = _loadPdf();
|
_documentLoaded = _loadPdf();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,14 +163,12 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Upload left page to server
|
// Upload left page to server
|
||||||
if (leftHasContent) {
|
|
||||||
_syncService.uploadAnnotation(
|
_syncService.uploadAnnotation(
|
||||||
sheetUuid: widget.sheet.uuid,
|
sheetUuid: widget.sheet.uuid,
|
||||||
page: _currentPage,
|
page: _currentPage,
|
||||||
annotationsJson: leftJson,
|
annotationsJson: leftJson,
|
||||||
lastModified: now,
|
lastModified: now,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
_leftDrawingController.markSaved();
|
_leftDrawingController.markSaved();
|
||||||
}
|
}
|
||||||
@@ -188,14 +188,12 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Upload right page to server
|
// Upload right page to server
|
||||||
if (rightHasContent) {
|
|
||||||
_syncService.uploadAnnotation(
|
_syncService.uploadAnnotation(
|
||||||
sheetUuid: widget.sheet.uuid,
|
sheetUuid: widget.sheet.uuid,
|
||||||
page: _currentPage + 1,
|
page: _currentPage + 1,
|
||||||
annotationsJson: rightJson,
|
annotationsJson: rightJson,
|
||||||
lastModified: now,
|
lastModified: now,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
_rightDrawingController.markSaved();
|
_rightDrawingController.markSaved();
|
||||||
}
|
}
|
||||||
@@ -214,7 +212,7 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _toggleFullscreen() {
|
void _toggleFullscreen() {
|
||||||
FullScreen.setFullScreen(!widget.config.fullscreen);
|
FullScreen.setFullScreen(!FullScreen.isFullScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -300,8 +298,9 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
widget.config.fullscreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
widget.config.fullscreen ? Icons.fullscreen_exit : Icons.fullscreen,
|
||||||
),
|
),
|
||||||
tooltip:
|
tooltip: widget.config.fullscreen
|
||||||
widget.config.fullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen',
|
? 'Exit Fullscreen'
|
||||||
|
: 'Enter Fullscreen',
|
||||||
onPressed: _toggleFullscreen,
|
onPressed: _toggleFullscreen,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -313,8 +312,9 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
widget.config.twoPageMode ? Icons.filter_1 : Icons.filter_2,
|
widget.config.twoPageMode ? Icons.filter_1 : Icons.filter_2,
|
||||||
),
|
),
|
||||||
tooltip:
|
tooltip: widget.config.twoPageMode
|
||||||
widget.config.twoPageMode ? 'Single Page Mode' : 'Two Page Mode',
|
? 'Single Page Mode'
|
||||||
|
: 'Two Page Mode',
|
||||||
onPressed: _toggleTwoPageMode,
|
onPressed: _toggleTwoPageMode,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -346,8 +346,9 @@ class _SheetViewerPageState extends State<SheetViewerPage>
|
|||||||
currentPageNumber: _currentPage,
|
currentPageNumber: _currentPage,
|
||||||
config: widget.config,
|
config: widget.config,
|
||||||
leftDrawingController: _leftDrawingController,
|
leftDrawingController: _leftDrawingController,
|
||||||
rightDrawingController:
|
rightDrawingController: widget.config.twoPageMode
|
||||||
widget.config.twoPageMode ? _rightDrawingController : null,
|
? _rightDrawingController
|
||||||
|
: null,
|
||||||
drawingEnabled: _isPaintMode,
|
drawingEnabled: _isPaintMode,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -364,10 +364,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: objective_c
|
name: objective_c
|
||||||
sha256: "983c7fa1501f6dcc0cb7af4e42072e9993cb28d73604d25ebf4dab08165d997e"
|
sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.2.5"
|
version: "9.3.0"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -617,10 +617,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.1"
|
version: "1.10.2"
|
||||||
sqflite:
|
sqflite:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 0.1.2
|
version: 0.2.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.0.0
|
sdk: ^3.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user