Skip to content

Commit

Permalink
feat: add sync fetch interval config
Browse files Browse the repository at this point in the history
  • Loading branch information
FriesI23 committed Feb 3, 2025
1 parent 3fc7ca8 commit cbe4dbc
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 61 deletions.
2 changes: 2 additions & 0 deletions lib/common/consts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../model/app_reminder_config.dart';
import '../model/app_sync_options.dart';
import '../model/habit_display.dart';
import '../model/habit_form.dart';
import '../theme/color.dart';
Expand Down Expand Up @@ -85,6 +86,7 @@ const defaultAppReminder = AppReminderConfig.off;
const defaultAppSyncTimeout = Duration(seconds: 60);
const defaultAppSyncConnectTimeout = Duration(seconds: 10);
const int? defaultAppSyncConnectRetryCount = null; // null for infinity
const defaultAppSyncFetchInterval = AppSyncFetchInterval.minute5;
//#endregion

//#region habit-field
Expand Down
38 changes: 38 additions & 0 deletions lib/model/app_sync_options.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2025 Fries_I23
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import '../common/enums.dart';

enum AppSyncFetchInterval implements EnumWithDBCode {
manual(null),
minute5(Duration(minutes: 5)),
minute15(Duration(minutes: 15)),
minute30(Duration(minutes: 30)),
hour1(Duration(hours: 1));

final Duration? t;

const AppSyncFetchInterval(this.t);

@override
int get dbCode => t?.inSeconds ?? -1;

static AppSyncFetchInterval? getFromDBCode(int dbCode,
{AppSyncFetchInterval? withDefault = AppSyncFetchInterval.manual}) {
for (var value in AppSyncFetchInterval.values) {
if (value.dbCode == dbCode) return value;
}
return withDefault;
}
}
41 changes: 41 additions & 0 deletions lib/persistent/profile/handler/app_sync.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

import 'dart:convert';

import '../../../common/consts.dart';
import '../../../common/types.dart';
import '../../../model/app_sync_options.dart';
import '../../../model/app_sync_server.dart';
import '../converter.dart';
import '../profile_helper.dart';
Expand All @@ -26,6 +28,45 @@ class AppSyncSwitchHandler extends ProfileHelperCovertToBoolHandler<bool> {
String get key => 'enableSync';
}

class AppSyncFetchIntervalHandler
extends ProfileHelperCovertToIntHandler<AppSyncFetchInterval> {
AppSyncFetchIntervalHandler(super.pref)
: super(codec: const AppSyncFetchIntervalCodec());

@override
String get key => 'syncFetchInterval';
}

final class AppSyncFetchIntervalCodec extends Codec<AppSyncFetchInterval, int> {
const AppSyncFetchIntervalCodec();

@override
Converter<int, AppSyncFetchInterval> get decoder =>
const _AppSyncFetchIntervalDecoder();

@override
Converter<AppSyncFetchInterval, int> get encoder =>
const _AppSyncFetchIntervalEncoder();
}

final class _AppSyncFetchIntervalEncoder
extends Converter<AppSyncFetchInterval, int> {
const _AppSyncFetchIntervalEncoder();

@override
int convert(AppSyncFetchInterval input) => input.dbCode;
}

final class _AppSyncFetchIntervalDecoder
extends Converter<int, AppSyncFetchInterval> {
const _AppSyncFetchIntervalDecoder();

@override
AppSyncFetchInterval convert(int input) =>
AppSyncFetchInterval.getFromDBCode(input,
withDefault: defaultAppSyncFetchInterval)!;
}

class AppSyncServerConfigHandler
extends ProfileHelperCovertToJsonHandler<AppSyncServer?> {
const AppSyncServerConfigHandler(super.pref,
Expand Down
17 changes: 16 additions & 1 deletion lib/provider/app_sync.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

import '../common/consts.dart';
import '../model/app_sync_options.dart';
import '../model/app_sync_server.dart';
import '../persistent/profile/handler/app_sync.dart';
import '../persistent/profile_provider.dart';
Expand All @@ -25,6 +27,7 @@ class AppSyncViewModel
implements ProviderMounted {
bool _mounted = true;
AppSyncSwitchHandler? _switch;
AppSyncFetchIntervalHandler? _interval;
AppSyncServerConfigHandler? _serverConfig;

@override
Expand All @@ -40,6 +43,7 @@ class AppSyncViewModel
void updateProfile(ProfileViewModel newProfile) {
super.updateProfile(newProfile);
_switch = newProfile.getHandler<AppSyncSwitchHandler>();
_interval = newProfile.getHandler<AppSyncFetchIntervalHandler>();
_serverConfig = newProfile.getHandler<AppSyncServerConfigHandler>();
}

Expand All @@ -48,7 +52,18 @@ class AppSyncViewModel
Future<void> setSyncSwitch(bool value, {bool listen = true}) async {
if (_switch?.get() != value) {
await _switch?.set(value);
notifyListeners();
if (listen) notifyListeners();
}
}

AppSyncFetchInterval get fetchInterval =>
_interval?.get() ?? defaultAppSyncFetchInterval;

Future<void> setFetchInterval(AppSyncFetchInterval value,
{bool listen = true}) async {
if (_interval?.get() != value) {
await _interval?.set(value);
if (listen) notifyListeners();
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/view/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class App extends StatelessWidget {
AppLanguageProfileHanlder.new,
AppSyncSwitchHandler.new,
AppSyncServerConfigHandler.new,
AppSyncFetchIntervalHandler.new,
];

const App({super.key});
Expand Down
16 changes: 16 additions & 0 deletions lib/view/for_app_sync/_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2025 Fries_I23
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export './app_sync_fetch_interval.dart'
show AppSyncFetchIntervalSwitchDialog, showAppSyncFetchIntervalSwitchDialog;
2 changes: 1 addition & 1 deletion lib/view/for_app_sync/_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.

export './app_sync_config_subgroup.dart';
export './app_sync_fetch_interval.dart' show AppSyncFetchIntervalTile;
export './app_sync_summary_tile.dart';
45 changes: 0 additions & 45 deletions lib/view/for_app_sync/app_sync_config_subgroup.dart

This file was deleted.

94 changes: 94 additions & 0 deletions lib/view/for_app_sync/app_sync_fetch_interval.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2025 Fries_I23
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../../l10n/localizations.dart';
import '../../model/app_sync_options.dart';
import '../../provider/app_sync.dart';

Future<AppSyncFetchInterval?> showAppSyncFetchIntervalSwitchDialog(
{required BuildContext context, AppSyncFetchInterval? select}) =>
showDialog(
context: context,
builder: (context) => AppSyncFetchIntervalSwitchDialog(select: select),
);

class AppSyncFetchIntervalSwitchDialog extends StatelessWidget {
final AppSyncFetchInterval? select;

const AppSyncFetchIntervalSwitchDialog({super.key, required this.select});

Widget _buildOption(BuildContext context, AppSyncFetchInterval interval,
[L10n? l10n]) =>
SimpleDialogOption(
key: ValueKey(interval.index),
onPressed: () => Navigator.of(context).pop(interval),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
switch (interval) {
AppSyncFetchInterval.manual => Text("Manual"),
AppSyncFetchInterval.minute5 => Text("5 Minutes"),
AppSyncFetchInterval.minute15 => Text("15 Minutes"),
AppSyncFetchInterval.minute30 => Text("30 Minutes"),
AppSyncFetchInterval.hour1 => Text("1 Hour"),
},
if (select == interval) const Icon(Icons.check),
],
),
);

@override
Widget build(BuildContext context) {
final l10n = L10n.of(context);
return SimpleDialog(
title: const Text("Fetch Interval"),
children: AppSyncFetchInterval.values
.map((e) => _buildOption(context, e, l10n))
.toList(),
);
}
}

class AppSyncFetchIntervalTile extends StatelessWidget {
final VoidCallback? onPressed;

const AppSyncFetchIntervalTile({super.key, this.onPressed});

Widget buildSubtitle() => Builder(
builder: (context) {
final interval =
context.select<AppSyncViewModel, AppSyncFetchInterval>(
(vm) => vm.fetchInterval);
return switch (interval) {
AppSyncFetchInterval.manual => Text("Manual"),
AppSyncFetchInterval.minute5 => Text("5 Minutes"),
AppSyncFetchInterval.minute15 => Text("15 Minutes"),
AppSyncFetchInterval.minute30 => Text("30 Minutes"),
AppSyncFetchInterval.hour1 => Text("1 Hour"),
};
},
);

@override
Widget build(BuildContext context) {
return ListTile(
title: const Text("Fetch Interval"),
subtitle: buildSubtitle(),
onTap: onPressed,
);
}
}
17 changes: 10 additions & 7 deletions lib/view/for_app_sync/app_sync_summary_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,39 @@

import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:provider/provider.dart';

import '../../model/app_sync_server.dart';
import '../../provider/app_sync.dart';

class AppSyncSummaryTile extends StatelessWidget {
final AppSyncServer? serverConfig;
final VoidCallback? onPressed;

const AppSyncSummaryTile({
super.key,
required this.serverConfig,
this.onPressed,
});

IconData? getSubTitleLeading(BuildContext context) =>
IconData? getSubTitleLeading(
BuildContext context, AppSyncServer? serverConfig) =>
switch (serverConfig?.type) {
AppSyncServerType.webdav => MdiIcons.cloudOutline,
AppSyncServerType.unknown => null,
_ => Icons.warning,
};

IconData? getTrailing(BuildContext context) => switch (serverConfig?.type) {
IconData? getTrailing(BuildContext context, AppSyncServer? serverConfig) =>
switch (serverConfig?.type) {
!= null => Icons.edit,
_ => Icons.add,
};

@override
Widget build(BuildContext context) {
final serverConfig = this.serverConfig;
final trailingData = getTrailing(context);
final subtileLeading = getSubTitleLeading(context);
final serverConfig = context
.select<AppSyncViewModel, AppSyncServer?>((vm) => vm.serverConfig);
final trailingData = getTrailing(context, serverConfig);
final subtileLeading = getSubTitleLeading(context, serverConfig);
return ListTile(
trailing: trailingData != null ? Icon(trailingData) : null,
title: Text("Sync Server"),
Expand Down
Loading

0 comments on commit cbe4dbc

Please sign in to comment.