Skip to content

Commit a74ca25

Browse files
committed
feat,fix: major changes in architecture and back up mechanism
1 parent e71bab0 commit a74ca25

26 files changed

+696
-306
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,5 @@ app.*.map.json
4848
# fvm
4949
.fvm
5050

51-
*.jks
51+
*.jks
52+
.env

android/app/build.gradle

+13
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,17 @@ android {
4545
targetSdkVersion 33
4646
versionCode flutterVersionCode.toInteger()
4747
versionName flutterVersionName
48+
multiDexEnabled true
4849
}
50+
51+
compileOptions {
52+
// Flag to enable support for the new language APIs
53+
coreLibraryDesugaringEnabled true
54+
// Sets Java compatibility to Java 8
55+
sourceCompatibility JavaVersion.VERSION_1_8
56+
targetCompatibility JavaVersion.VERSION_1_8
57+
}
58+
4959
signingConfigs {
5060
release {
5161
keyAlias keystoreProperties['keyAlias']
@@ -71,4 +81,7 @@ flutter {
7181

7282
dependencies {
7383
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
84+
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2'
85+
implementation 'androidx.window:window:1.0.0'
86+
implementation 'androidx.window:window-java:1.0.0'
7487
}

android/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
}
77

88
dependencies {
9-
classpath 'com.android.tools.build:gradle:7.1.2'
9+
classpath 'com.android.tools.build:gradle:7.3.1'
1010
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1111
}
1212
}

devtools_options.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extensions:

lib/database/config.dart

+23-22
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,54 @@
1-
import 'package:flutter/foundation.dart';
1+
import 'dart:async';
2+
23
import 'package:flutter_riverpod/flutter_riverpod.dart';
4+
import 'package:heartry/models/config_model/config_model.dart';
35
import 'package:shared_preferences/shared_preferences.dart';
46

5-
import '../init_get_it.dart';
6-
7-
final configProvider = ChangeNotifierProvider<Config>((_) => locator<Config>());
7+
final configProvider =
8+
AsyncNotifierProvider<Config, ConfigModel>(() => Config());
89

9-
class Config extends ChangeNotifier {
10+
class Config extends AsyncNotifier<ConfigModel> {
1011
static late SharedPreferences _sharedPrefs;
1112

1213
static const String _nameKey = "name";
1314
static const String _profileKey = "profile";
1415
static const String _lastBackupKey = "lastBackup";
1516

16-
Future<void> init() async {
17-
_sharedPrefs = await SharedPreferences.getInstance();
18-
}
19-
2017
set lastBackup(DateTime? dateTime) {
2118
_sharedPrefs.setString(_lastBackupKey, dateTime!.toIso8601String());
22-
notifyListeners();
23-
}
24-
25-
DateTime? get lastBackup {
26-
final lastBackup = _sharedPrefs.getString(_lastBackupKey);
27-
if (lastBackup == null) return null;
28-
29-
return DateTime.parse(lastBackup);
19+
state = state.whenData((value) => value.copyWith(lastBackup: dateTime));
3020
}
3121

3222
set name(String? value) {
3323
if (value == null) return;
3424

3525
_sharedPrefs.setString(_nameKey, value);
36-
notifyListeners();
26+
state = state.whenData((data) => data.copyWith(name: value));
3727
}
3828

39-
String? get name => _sharedPrefs.getString(_nameKey);
40-
4129
set profile(String? value) {
4230
if (value == null) {
4331
_sharedPrefs.remove(_profileKey);
44-
notifyListeners();
32+
state = state.whenData((data) => data.copyWith(profile: null));
4533

4634
return;
4735
}
4836
_sharedPrefs.setString(_profileKey, value);
49-
notifyListeners();
37+
state = state.whenData((data) => data.copyWith(profile: value));
5038
}
5139

5240
String? get profile => _sharedPrefs.getString(_profileKey);
41+
42+
@override
43+
FutureOr<ConfigModel> build() async {
44+
_sharedPrefs = await SharedPreferences.getInstance();
45+
46+
return ConfigModel(
47+
name: _sharedPrefs.getString(_nameKey) ?? "User",
48+
profile: _sharedPrefs.getString(_profileKey),
49+
lastBackup: _sharedPrefs.getString(_lastBackupKey) != null
50+
? DateTime.parse(_sharedPrefs.getString(_lastBackupKey)!)
51+
: null,
52+
);
53+
}
5354
}

lib/database/database.g.dart

+3-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/main.dart

+27-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:catcher_2/catcher_2.dart';
22
import 'package:flutter/material.dart';
33
import 'package:flutter/services.dart';
4+
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
45
import 'package:flutter_riverpod/flutter_riverpod.dart';
56

67
import 'database/config.dart';
@@ -10,10 +11,14 @@ import 'screens/intro_screen/intro_screen.dart';
1011
import 'screens/poems_screen/poems_screen.dart';
1112
import 'utils/custom_email_report_handler.dart';
1213
import 'utils/theme.dart';
14+
import 'utils/workmanager_helper.dart';
1315
import 'widgets/color_scheme_builder.dart';
1416

1517
Future<void> main() async {
18+
WidgetsFlutterBinding.ensureInitialized();
19+
1620
initGetIt();
21+
initWorkmanager();
1722

1823
final releaseCatcher = Catcher2Options(
1924
DialogReportMode(),
@@ -45,12 +50,15 @@ class MyApp extends StatefulWidget {
4550
}
4651

4752
class _MyAppState extends State<MyApp> {
48-
late Future<void> _initSharedPrefs;
49-
5053
@override
5154
void initState() {
5255
super.initState();
53-
_initSharedPrefs = locator<Config>().init();
56+
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
57+
FlutterLocalNotificationsPlugin();
58+
flutterLocalNotificationsPlugin
59+
.resolvePlatformSpecificImplementation<
60+
AndroidFlutterLocalNotificationsPlugin>()!
61+
.requestNotificationsPermission();
5462
}
5563

5664
@override
@@ -71,22 +79,23 @@ class _MyAppState extends State<MyApp> {
7179
darkTheme: theme.themeType == ThemeType.dark
7280
? getDarkTheme(darkColorScheme)
7381
: getBlackTheme(darkColorScheme),
74-
home: FutureBuilder(
75-
future: _initSharedPrefs,
76-
builder: (context, snapshot) {
77-
if (snapshot.connectionState == ConnectionState.done) {
78-
final name = locator<Config>().name;
79-
80-
if (name != null) return const PoemScreen();
81-
82-
return const IntroScreen();
83-
}
82+
home: Consumer(
83+
builder: (context, ref, _) {
84+
return ref.watch(configProvider).when(
85+
data: (config) {
86+
if (config.name != null) return const PoemScreen();
8487

85-
return const Material(
86-
child: Center(
87-
child: CircularProgressIndicator(),
88-
),
89-
);
88+
return const IntroScreen();
89+
},
90+
error: (err, st) => Center(
91+
child: Text("$err\n${"_" * 25}\n$st"),
92+
),
93+
loading: () => const Material(
94+
child: Center(
95+
child: CircularProgressIndicator(),
96+
),
97+
),
98+
);
9099
},
91100
),
92101
);

lib/models/backup_model/backup_model.dart

+4-21
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,24 @@ import 'package:heartry/models/converters.dart';
22
import 'package:json_annotation/json_annotation.dart';
33

44
import '../../database/database.dart';
5-
import '../theme_detail_model/theme_detail_model.dart';
65

76
part 'backup_model.g.dart';
87

98
@JsonSerializable()
109
class BackupModel {
1110
const BackupModel({
1211
required this.poems,
13-
required this.theme,
14-
required this.config,
12+
required this.prefs,
13+
required this.image,
1514
});
1615

1716
@PoemModelConverter()
1817
final List<PoemModel> poems;
19-
final ThemeDetailModel theme;
20-
final ConfigModel config;
18+
final Map<String, dynamic> prefs;
19+
final List<int>? image;
2120

2221
factory BackupModel.fromJson(Map<String, dynamic> json) =>
2322
_$BackupModelFromJson(json);
2423

2524
Map<String, dynamic> toJson() => _$BackupModelToJson(this);
2625
}
27-
28-
@JsonSerializable()
29-
class ConfigModel {
30-
const ConfigModel({
31-
required this.name,
32-
required this.image,
33-
});
34-
35-
final String name;
36-
final List<int>? image;
37-
38-
factory ConfigModel.fromJson(Map<String, dynamic> json) =>
39-
_$ConfigModelFromJson(json);
40-
41-
Map<String, dynamic> toJson() => _$ConfigModelToJson(this);
42-
}

lib/models/backup_model/backup_model.g.dart

+3-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import 'package:json_annotation/json_annotation.dart';
2+
3+
import '../converters.dart';
4+
5+
part 'config_model.g.dart';
6+
7+
@JsonSerializable()
8+
class ConfigModel {
9+
final String? name;
10+
final String? profile;
11+
@DateTimeConverter()
12+
final DateTime? lastBackup;
13+
14+
ConfigModel({
15+
required this.name,
16+
this.profile,
17+
this.lastBackup,
18+
});
19+
20+
factory ConfigModel.fromJson(Map<String, dynamic> json) =>
21+
_$ConfigModelFromJson(json);
22+
23+
Map<String, dynamic> toJson() => _$ConfigModelToJson(this);
24+
25+
ConfigModel copyWith({
26+
String? name,
27+
String? profile,
28+
DateTime? lastBackup,
29+
}) {
30+
return ConfigModel(
31+
name: name ?? this.name,
32+
profile: profile ?? this.profile,
33+
lastBackup: lastBackup ?? this.lastBackup,
34+
);
35+
}
36+
}

lib/models/config_model/config_model.g.dart

+34
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/models/converters.dart

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ import 'package:json_annotation/json_annotation.dart';
33

44
import '../database/database.dart';
55

6+
class DateTimeConverter extends JsonConverter<DateTime, String> {
7+
const DateTimeConverter();
8+
9+
@override
10+
DateTime fromJson(String json) => DateTime.parse(json);
11+
12+
@override
13+
String toJson(DateTime object) => object.toIso8601String();
14+
}
15+
616
class NullableColorConverter extends JsonConverter<Color?, int?> {
717
const NullableColorConverter();
818

0 commit comments

Comments
 (0)