Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import 'package:wger/providers/nutrition.dart';
import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/auth_screen.dart';
import 'package:wger/screens/dashboard.dart';
import 'package:wger/screens/exercises_screen.dart';
import 'package:wger/screens/form_screen.dart';
import 'package:wger/screens/gallery_screen.dart';
import 'package:wger/screens/gym_mode.dart';
Expand Down Expand Up @@ -129,6 +130,7 @@ class MyApp extends StatelessWidget {
WeightScreen.routeName: (ctx) => WeightScreen(),
WorkoutPlanScreen.routeName: (ctx) => WorkoutPlanScreen(),
WorkoutPlansScreen.routeName: (ctx) => WorkoutPlansScreen(),
ExercisesScreen.routeName: (ctx) => ExercisesScreen(),
},
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
Expand Down
10 changes: 10 additions & 0 deletions lib/models/exercises/category.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,14 @@ class ExerciseCategory {
// Boilerplate
factory ExerciseCategory.fromJson(Map<String, dynamic> json) => _$ExerciseCategoryFromJson(json);
Map<String, dynamic> toJson() => _$ExerciseCategoryToJson(this);

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;

return other is ExerciseCategory && other.id == id && other.name == name;
}

@override
int get hashCode => id.hashCode ^ name.hashCode;
}
7 changes: 7 additions & 0 deletions lib/providers/exercises.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ class ExercisesProvider extends WgerBaseProvider with ChangeNotifier {
return [..._exercises];
}

List<Exercise> findByCategory(ExerciseCategory? category) {
if (category == null) return this.items;
return this.items.where((exercise) => exercise.categoryObj == category).toList();
}

List<ExerciseCategory> get categories => _categories;

/// Returns an exercise
Exercise findById(int exerciseId) {
return _exercises.firstWhere((exercise) => exercise.id == exerciseId);
Expand Down
96 changes: 96 additions & 0 deletions lib/screens/exercises_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:wger/models/exercises/category.dart';
import 'package:wger/providers/exercises.dart';
import 'package:wger/widgets/core/app_bar.dart';
import 'package:wger/widgets/exercises/list_tile.dart';

class ExercisesScreen extends StatefulWidget {
const ExercisesScreen({Key? key}) : super(key: key);
static const routeName = '/exercises';

@override
_ExercisesScreenState createState() => _ExercisesScreenState();
}

class _ExercisesScreenState extends State<ExercisesScreen> {
ExerciseCategory? _category;

List<DropdownMenuItem<ExerciseCategory>> _categoryOptions() {
return Provider.of<ExercisesProvider>(context, listen: false)
.categories
.map<DropdownMenuItem<ExerciseCategory>>(
(category) {
return DropdownMenuItem<ExerciseCategory>(
child: Text(category.name),
value: category,
);
},
).toList();
}

@override
Widget build(BuildContext context) {
final exercisesList =
Provider.of<ExercisesProvider>(context, listen: false).findByCategory(_category);
final size = MediaQuery.of(context).size;

return Scaffold(
appBar: WgerAppBar('Exercises'),
body: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 15),
child: Row(
children: [
Expanded(
child: DropdownButtonFormField<ExerciseCategory>(
hint: Text('All Exercises'),
value: _category,
items: _categoryOptions(),
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
onChanged: (ExerciseCategory? newCategory) {
setState(() {
_category = newCategory;
});
},
),
),
Row(
children: [
IconButton(onPressed: () {}, icon: Icon(Icons.search)),
IconButton(onPressed: () {}, icon: Icon(Icons.filter_alt)),
],
)
],
),
),
Expanded(
child: ListView.separated(
separatorBuilder: (context, index) {
return Divider(
thickness: 1,
);
},
itemCount: exercisesList.length,
itemBuilder: (context, index) {
final exercise = exercisesList[index];
return Container(
height: size.height * 0.175,
child: ExerciseListTile(exercise: exercise),
);
},
),
)
],
),
);
}
}
4 changes: 3 additions & 1 deletion lib/screens/home_tabs_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import 'package:wger/providers/measurement.dart';
import 'package:wger/providers/nutrition.dart';
import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/dashboard.dart';
import 'package:wger/screens/exercises_screen.dart';
import 'package:wger/screens/gallery_screen.dart';
import 'package:wger/screens/nutritional_plans_screen.dart';
import 'package:wger/screens/weight_screen.dart';
Expand Down Expand Up @@ -63,7 +64,8 @@ class _HomeTabsScreenState extends State<HomeTabsScreen> with SingleTickerProvid
final _screenList = <Widget>[
DashboardScreen(),
WorkoutPlansScreen(),
NutritionScreen(),
// Replaced [NutritionScreen] for debugging purposes
ExercisesScreen(),
WeightScreen(),
GalleryScreen(),
];
Expand Down
59 changes: 59 additions & 0 deletions lib/widgets/exercises/list_tile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/widgets/exercises/images.dart';

class ExerciseListTile extends StatelessWidget {
const ExerciseListTile({Key? key, required this.exercise}) : super(key: key);

final Exercise exercise;

@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final theme = Theme.of(context);

return Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: size.width * 0.3,
child: Center(
child: ExerciseImageWidget(
image: exercise.getMainImage,
),
),
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 7),
decoration: BoxDecoration(
color: theme.primaryColorLight.withOpacity(0.15),
border: Border.all(color: Colors.grey[300]!),
borderRadius: BorderRadius.circular(5),
),
child: Text(
exercise.categoryObj.name,
),
),
Text(
exercise.name,
style: theme.textTheme.headline5,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
Text(
exercise.equipment.map((equipment) => equipment.name).join(", "),
)
],
),
)
],
);
}
}