Skip to content

Commit

Permalink
Added overview page feature (#402)
Browse files Browse the repository at this point in the history
* Created simple floating overview button with page

* Added toy overview page with fancy visuals

* Tried to add relevant stuff to overview

* Refactored code

* Made overview working

* Bump v0.13.0+63

* Fix axisSide issue

* Linted code
  • Loading branch information
andreped authored Jan 7, 2025
1 parent ea932e4 commit 2ee0659
Show file tree
Hide file tree
Showing 8 changed files with 539 additions and 58 deletions.
126 changes: 118 additions & 8 deletions lib/core/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,12 @@ class DatabaseHelper {

Future<void> restoreDatabase(BuildContext context) async {
try {
String file_path;
String filePath;
if (Platform.isIOS) {
final directory = await getApplicationDocumentsDirectory();
file_path = '${directory.path}/backup_database.db';
filePath = '${directory.path}/backup_database.db';
} else if (Platform.isAndroid) {
file_path = '/storage/emulated/0/Download/backup_database.db';
filePath = '/storage/emulated/0/Download/backup_database.db';

// Use file picker to select the backup file
FilePickerResult? result = await FilePicker.platform.pickFiles(
Expand All @@ -616,13 +616,13 @@ class DatabaseHelper {
return;
}

file_path = result.files.single.path!;
filePath = result.files.single.path!;
} else {
throw Exception('Unsupported platform');
}

// Check if the backup file exists
File selectedFile = File(file_path);
File selectedFile = File(filePath);
if (!await selectedFile.exists()) {
print('File does not exist');
await _showDialog(context, 'Restore Failed', 'File does not exist');
Expand All @@ -633,7 +633,7 @@ class DatabaseHelper {
String dbPath = await _databasePath();

// Open the backup database
Database backupDb = await openDatabase(file_path);
Database backupDb = await openDatabase(filePath);

// Open the destination database
Database destinationDb = await openDatabase(dbPath);
Expand Down Expand Up @@ -676,9 +676,9 @@ class DatabaseHelper {
// Close the backup database after transferring records
await backupDb.close();

print('Database restored successfully from $file_path');
print('Database restored successfully from $filePath');
await _showDialog(context, 'Restore Successful',
'Database restored successfully from $file_path');
'Database restored successfully from $filePath');
} catch (e) {
print('Failed to restore database: $e');
await _showDialog(
Expand Down Expand Up @@ -708,4 +708,114 @@ class DatabaseHelper {
},
);
}

Future<double> getTotalWeightLifted() async {
final db = await database;
final result = await db.rawQuery('''
SELECT SUM(CAST(weight AS REAL) * reps * sets) as totalWeight
FROM exercises
''');
return result.isNotEmpty ? result.first['totalWeight'] as double : 0.0;
}

Future<String> getMostCommonExercise() async {
final db = await database;
final result = await db.rawQuery('''
SELECT exercise, COUNT(*) as count
FROM exercises
GROUP BY exercise
ORDER BY count DESC
LIMIT 1
''');
return result.isNotEmpty ? result.first['exercise'] as String : '';
}

Future<Map<String, double>> getPersonalRecords() async {
final db = await database;
final result = await db.rawQuery('''
SELECT exercise, MAX(CAST(weight AS REAL)) as maxWeight
FROM exercises
GROUP BY exercise
ORDER BY maxWeight DESC
LIMIT 3
''');

Map<String, double> personalRecords = {};
for (var row in result) {
personalRecords[row['exercise'] as String] = row['maxWeight'] as double;
}

return personalRecords;
}

Future<List<Map<String, dynamic>>> getRecentActivity() async {
final db = await database;
final result = await db.rawQuery('''
SELECT exercise, weight, reps, sets, timestamp
FROM exercises
ORDER BY timestamp DESC
LIMIT 1
''');
return result;
}

Future<List<Map<String, dynamic>>> getWeightProgress() async {
final db = await database;
final result = await db.rawQuery('''
SELECT timestamp, CAST(weight AS REAL) as weight
FROM fitness
ORDER BY timestamp ASC
''');
return result;
}

Future<List<Map<String, dynamic>>> getExerciseFrequency() async {
final db = await database;
final result = await db.rawQuery('''
SELECT date(timestamp) as day, COUNT(*) as count
FROM exercises
GROUP BY day
ORDER BY day ASC
''');
return result;
}

Future<List<Map<String, dynamic>>> getNewHighScores() async {
final db = await database;
final result = await db.rawQuery('''
SELECT exercise, MAX(CAST(weight AS REAL)) as maxWeight
FROM exercises
GROUP BY exercise
ORDER BY timestamp DESC
LIMIT 5
''');
return result;
}

Future<Map<String, double>> getTotalAndAverageTrainingTime() async {
final db = await database;
final result = await db.rawQuery('''
SELECT date(timestamp) as day, MIN(timestamp) as firstExercise, MAX(timestamp) as lastExercise
FROM exercises
GROUP BY day
''');

double totalTrainingTime = 0.0;
int trainingDays = result.length;

for (var row in result) {
DateTime firstExercise = DateTime.parse(row['firstExercise'] as String);
DateTime lastExercise = DateTime.parse(row['lastExercise'] as String);
totalTrainingTime += lastExercise.difference(firstExercise).inMinutes /
60.0; // Convert minutes to hours
}

double averageTrainingTime =
trainingDays > 0 ? totalTrainingTime / trainingDays : 0.0;

return {
'totalTrainingTime': totalTrainingTime,
'averageTrainingTime': averageTrainingTime,
};
}
}
93 changes: 56 additions & 37 deletions lib/tabs/home_tab.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'summary_tab.dart';
import '../widgets/settings/settings.dart';
import 'table_tab.dart';
import 'records_tab.dart';
import 'overview_page.dart';

class ExerciseStoreApp extends StatelessWidget {
final AppTheme appTheme;
Expand Down Expand Up @@ -163,45 +164,63 @@ class ExerciseStoreHomePageState extends State<ExerciseStoreHomePage>
),
],
),
body: PageStorage(
bucket: bucket,
child: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
onPageChanged: (index) {
_tabController.animateTo(index);
},
children: [
RecordsTab(
isKg: widget.isKg,
bodyweightEnabledGlobal: widget.bodyweightEnabledGlobal),
SummaryTab(
selectedDay: _selectedDay,
onDateSelected: _onDateSelected,
isKg: widget.isKg,
bodyweightEnabledGlobal: widget.bodyweightEnabledGlobal,
),
Padding(
padding: const EdgeInsets.all(16.0),
child: ExerciseSetter(
isKg: widget.isKg,
onExerciseAdded: () {
setState(() {});
},
),
body: Stack(
children: [
PageStorage(
bucket: bucket,
child: PageView(
controller: _pageController,
physics: const NeverScrollableScrollPhysics(),
onPageChanged: (index) {
_tabController.animateTo(index);
},
children: [
RecordsTab(
isKg: widget.isKg,
bodyweightEnabledGlobal: widget.bodyweightEnabledGlobal),
SummaryTab(
selectedDay: _selectedDay,
onDateSelected: _onDateSelected,
isKg: widget.isKg,
bodyweightEnabledGlobal: widget.bodyweightEnabledGlobal,
),
Padding(
padding: const EdgeInsets.all(16.0),
child: ExerciseSetter(
isKg: widget.isKg,
onExerciseAdded: () {
setState(() {});
},
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: VisualizationTab(
isKg: widget.isKg,
bodyweightEnabledGlobal: widget.bodyweightEnabledGlobal,
defaultAggregationMethod: widget.aggregationMethod,
defaultChartType: widget.plotType,
),
),
TableTab(isKg: widget.isKg),
],
),
Padding(
padding: const EdgeInsets.all(16.0),
child: VisualizationTab(
isKg: widget.isKg,
bodyweightEnabledGlobal: widget.bodyweightEnabledGlobal,
defaultAggregationMethod: widget.aggregationMethod,
defaultChartType: widget.plotType,
),
),
Positioned(
bottom: 10.0,
left: 30.0,
child: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => OverviewPage()),
);
},
backgroundColor: theme.colorScheme.primary,
child: const Icon(Icons.info_outline, color: Colors.white),
),
TableTab(isKg: widget.isKg),
],
),
),
],
),
bottomNavigationBar: BottomAppBar(
child: TabBar(
Expand Down
Loading

0 comments on commit 2ee0659

Please sign in to comment.