Skip to content

Commit

Permalink
feat: #3
Browse files Browse the repository at this point in the history
  • Loading branch information
orl0pl committed Oct 20, 2024
1 parent 4c6e2fc commit d6152d1
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 9 deletions.
61 changes: 57 additions & 4 deletions lib/data/database_helper.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:maximum/data/models/appopen.dart';
import 'package:maximum/data/models/note.dart';
import 'package:maximum/data/models/task.dart';
import 'package:maximum/data/models/place.dart';
Expand All @@ -23,11 +24,16 @@ class DatabaseHelper {
return _database!;
}

Future<Database> _initDatabase() async {
Future<String> getDatabasePath() async {
String path = join(await getDatabasesPath(), 'data.db');
return path;
}

Future<Database> _initDatabase() async {
String path = await getDatabasePath();
return await openDatabase(
path,
version: 1,
version: 2,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
Expand Down Expand Up @@ -137,9 +143,31 @@ class DatabaseHelper {
PRIMARY KEY(noteId, tagId)
)
''');
}

Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {}
if (version == 2) {
await db.execute('''
CREATE TABLE AppOpen (
datetime INTEGER NOT NULL PRIMARY KEY,
packageName TEXT NOT NULL,
weekQuarter INTEGER NOT NULL,
openedVia INTEGER NOT NULL -- 0: app list, 1: search
);
''');
}
}

Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion == 1 && newVersion == 2) {
await db.execute('''
CREATE TABLE AppOpen (
datetime INTEGER NOT NULL PRIMARY KEY,
packageName TEXT NOT NULL,
weekQuarter INTEGER NOT NULL,
openedVia INTEGER NOT NULL -- 0: app list, 1: search
);
''');
}
}

Future<Task?> getTask(int taskId) async {
Database db = await database;
Expand Down Expand Up @@ -260,6 +288,26 @@ class DatabaseHelper {
return maps.map((e) => TaskStatus.fromMap(e)).toList();
}

Future<Map<String, int>> getRecentAppOpensMapPackageNameCount() async {
Database db = await database;
List<Map<String, dynamic>> maps = await db.rawQuery('''
SELECT packageName, COUNT(*) as count
FROM AppOpen
WHERE datetime > ?
AND weekQuarter = ?
GROUP BY packageName
''', [
DateTime.now().millisecondsSinceEpoch - 2629746000,
getWeekQuarter(DateTime.now())
]);

Map<String, int> map = {};
for (var element in maps) {
map[element['packageName']] = element['count'];
}
return map;
}

Future<int> insertTask(Task task) async {
Database db = await database;
return await db.insert('Task', task.toMap());
Expand Down Expand Up @@ -290,6 +338,11 @@ class DatabaseHelper {
return await db.insert('NoteTag', noteTag.toMap());
}

Future<int> insertAppOpen(AppOpen appOpen) async {
Database db = await database;
return await db.insert('AppOpen', appOpen.toMap());
}

Future<int> addTagToTask(int taskId, int tagId) async {
Database db = await database;
return await db.insert('TaskTag_Task', {'taskId': taskId, 'tagId': tagId});
Expand Down
39 changes: 39 additions & 0 deletions lib/data/models/appopen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
enum AppOpenOpenedVia { appList, search }

int getWeekQuarter(DateTime date) {
DateTime lastMonday =
date.subtract(Duration(days: (date.weekday - 1 + 7) % 7 + 7));
return (date.difference(lastMonday).inMinutes / 15).floor();
}

class AppOpen {
final DateTime datetime;
final String packageName;
final int weekQuarter; // floor(minutes_since_monday_midnight / 15)
final AppOpenOpenedVia openedVia;

AppOpen({
required this.datetime,
required this.packageName,
required this.weekQuarter,
required this.openedVia,
});

factory AppOpen.fromMap(Map<String, dynamic> map) {
return AppOpen(
datetime: DateTime.fromMillisecondsSinceEpoch(map['datetime'] as int),
packageName: map['packageName'] as String,
weekQuarter: map['weekQuarter'] as int,
openedVia: AppOpenOpenedVia.values[map['openedVia'] as int],
);
}

Map<String, dynamic> toMap() {
return {
'datetime': datetime.millisecondsSinceEpoch,
'packageName': packageName,
'weekQuarter': weekQuarter,
'openedVia': openedVia.index,
};
}
}
57 changes: 52 additions & 5 deletions lib/widgets/subscreens/apps.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:app_launcher/app_launcher.dart';
import 'package:flutter/material.dart';
import 'package:fuzzy/fuzzy.dart';
import 'package:maximum/data/database_helper.dart';
import 'package:maximum/data/models/appopen.dart';
import 'package:maximum/data/models/note.dart';
import 'package:intl/intl.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Expand Down Expand Up @@ -51,7 +52,7 @@ class AppsWidget extends StatefulWidget {

class AppsWidgetState extends State<AppsWidget> {
List<Element> allMatches = [];

Map<String, int>? appOpenMap;
bool notesLoaded = false;
List<Note> allnotes = [];

Expand Down Expand Up @@ -80,17 +81,37 @@ class AppsWidgetState extends State<AppsWidget> {
return false;
}

void fetchAppOpenMap() async {
appOpenMap = await DatabaseHelper().getRecentAppOpensMapPackageNameCount();
if (mounted) {
setState(() {
appOpenMap = appOpenMap;
});
}
}

@override
Widget build(BuildContext context) {
AppLocalizations l = AppLocalizations.of(context);
void initState() {
super.initState();

fetchAppOpenMap();
fetchElements();
}

void fetchElements() {
if (!notesLoaded) {
DatabaseHelper().notes.then((notes) async {
allnotes = notes;
});
}

if (widget.inputValue.isEmpty) {
allMatches = widget.apps.map((e) => Element.fromApp(e)).toList();
allMatches = widget.apps.map((e) => Element.fromApp(e)).toList()
..sort((a, b) {
int? appOpenCountA = appOpenMap?[a.app!.packageName] ?? 0;
int? appOpenCountB = appOpenMap?[b.app!.packageName] ?? 0;
return appOpenCountB.compareTo(appOpenCountA);
});
} else {
Fuzzy<Element> fuse = Fuzzy(
allnotes.map((e) => (Element.fromNote(e))).toList() +
Expand All @@ -110,7 +131,12 @@ class AppsWidgetState extends State<AppsWidget> {
final matches = fuse.search(widget.inputValue.toLowerCase());
allMatches = matches.map((e) => e.item).toList();
}
}

@override
Widget build(BuildContext context) {
AppLocalizations l = AppLocalizations.of(context);
fetchElements();
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
Expand Down Expand Up @@ -144,7 +170,13 @@ class AppsWidgetState extends State<AppsWidget> {
itemBuilder: (context, index) {
if (allMatches[index].type == ElementType.app) {
return AppListEntry(
widget: widget, app: allMatches[index].app!);
widget: widget,
app: allMatches[index].app!,
appOpenCount: appOpenMap?[
allMatches[index].app!.packageName!] ??
0,
isInSearchMode: widget.inputValue != "",
);
} else if (allMatches[index].type ==
ElementType.note) {
return ListTile(
Expand Down Expand Up @@ -221,6 +253,8 @@ class AppListEntry extends StatelessWidget {
super.key,
required this.widget,
required this.app,
required this.appOpenCount,
this.isInSearchMode = false,
this.highlight = false,
});

Expand All @@ -229,6 +263,10 @@ class AppListEntry extends StatelessWidget {

final bool highlight;

final int? appOpenCount;

final bool isInSearchMode;

@override
Widget build(BuildContext context) {
return ListTile(
Expand Down Expand Up @@ -260,6 +298,7 @@ class AppListEntry extends StatelessWidget {
}
},
),
//subtitle: appOpenCount == null ? null : Text("$appOpenCount"),
//subtitle: Text(appCategoryFromInt(app.category ?? -1).toString()),
trailing: highlight ? const Icon(Icons.chevron_right) : null,
title: FutureBuilder<String?>(
Expand All @@ -280,6 +319,14 @@ class AppListEntry extends StatelessWidget {
},
),
onTap: () async {
DatabaseHelper().insertAppOpen(AppOpen(
packageName: app.packageName!,
datetime: DateTime.now(),
weekQuarter: getWeekQuarter(DateTime.now()),
openedVia: isInSearchMode
? AppOpenOpenedVia.search
: AppOpenOpenedVia.appList,
));
AndroidPackageManager().openApp(app.packageName!);
},
);
Expand Down

0 comments on commit d6152d1

Please sign in to comment.