Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plate 46 calc #688

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Conversation

AyushJagaty
Copy link

Description (Proposed Changes)

-Allow users to input their preferred bar weight and available plate weights in both kilograms and pounds.
-Calculate the optimal plate combination for a given target weight, considering the user's custom bar and plate weights.

Link to the issue : #46

@rolandgeider
Copy link
Member

thanks for the PR, I'll review it next week

plateProvider.setWeight(num.parse(_weightController.text));
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>const AddPlateWeights()));
},
child: const Text("Enter custom Denomination's")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make this a bit less prominent, a gear icon left to "Plates" would probably be enough

appBar: AppBar (
title: const Text('Enter Custom Plate Weights'),
),
body: Column (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure there is enough margin on the right side of the screen as well (or wrap around if there's not enough space). Also I would name the dropdown something like "preferred unit". If you want, you can extract this info from the profile from the UserProvider (the isMetric).

Bildschirmfoto 2024-12-12 um 13 02 35

notifyListeners();
}

void toggleSelection(num x) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would save the selected weights to the device, then we don't need to add this every time. You can simply save the array to SharedPreferences (just dump it as a string and later read from that)

Copy link
Author

@AyushJagaty AyushJagaty Dec 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am encountering difficulties in calculating plate denominations using the saved plate weight denominations while implementing shared preferences.

I've explored several approaches:

Async Function in initState(): I attempted to call an async function containing await loadFromSharedPref() within the initState() of my widget. However, this resulted in widget.getPlates executing before loadFromSharedPref(), leading to an empty list being displayed initially but it is being shown inside the slider selection menu.

Calling loadFromSharedPref() from main(): I tried calling loadFromSharedPref() from the main() function to ensure it executed before widget.getPlates. While this successfully loaded and printed the saved values in the main() function, the widget.getPlates still displayed an empty list but it is being shown inside the slider selection menu.

Flag in PlateWeightsProvider: I introduced a flag (loadedFromSharedPref) within the PlateWeightsProvider, setting it to true after loadFromSharedPref() completes. In widget.getPlates, I attempted to wait for the flag to become true before displaying the plate denominations. Unfortunately, this approach also failed to display the saved results correctly, and I'm now unable to select/deselect any options or reset them.
I've attached screenshots of the relevant functions for further clarity.

I would greatly appreciate any guidance or suggestions on how to effectively load and display shared preferences within my PlateWeightsProvider and ensure proper functionality within my widgets.

declared_in_main
flutter 2
Untitled 3

Screen.Recording.2024-12-22.at.4.36.30.PM.mov

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mhh, hadn't thought this would cause problems. I'll take a look!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AyushJagaty I got this to work by calling the prefs loader on initstate on the widget (the method itself is also simpler than yours, I think we can get away with just catching some errors and returning an empty list)

in the provider

  void readPlates() async {
    final prefs = await SharedPreferences.getInstance();
    final platePrefData = prefs.getString(PREFS_PLATES);
    if (platePrefData != null) {
      final plateData = json.decode(platePrefData);
      selectedWeights = plateData.cast<num>();
    }
    notifyListeners();
  }
  
 Future<void> toggleSelection(num x) async {
    ...
    final prefs = await SharedPreferences.getInstance();
    final plateData = json.encode(selectedWeights);
    prefs.setString(PREFS_PLATES, plateData);
  }

in the plate widget:

class _AddPlateWeightsState extends State<AddPlateWeights> {
  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      Provider.of<PlateWeights>(context, listen: false).readPlates();
    });
  }
  ...
  }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi wish you a very Happy New Year!!! I tried this approach and i had also tried a similar approach calling from the initstate(it was the first approach which i had mentioned in the previous message but it was more complex than yours .... thanks i could learn something new from your approach).
This approach also resulted in a similar situation resulting in widget getPlates executing before readPlates(), leading to display the denominations according to the default weights initially but the selected ones are being shown inside the slider selection menu. As in this approach it is being called from AddPlateWeights where as AddPlateWeights gets called when I tap on the gear icon(icon for selecting the available plates). I also tried calling from the initstate of _LogPageState of gym_mode.dart as we want to receive the result without tapping the gear icon but it resulted in the same situation(widget getPlates executing before readPlates(), leading to display the denominations according to the default weights initially but the selected ones are being shown inside the slider selection menu).

I had tried with both the readPlates provided code and with a modified readPlates function with catching some errors and returning an empty list -

void readPlates() async{
    final pref = await SharedPreferences.getInstance();
    final platePrefData = pref.getString('selectedPlates');
    if(platePrefData != null){
        try{
            final plateData = json.decode(platePrefData);
            if(plateData is List){
              selectedWeights = plateData.cast<num>();
            }else{
              throw const FormatException('Not a List');
            }
        }catch(e){
          selectedWeights = [];
        }
    }
    print('loaded');
    notifyListeners();
  }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

happy new year to you too!! It's probably easier if you push the updated code and tell me what to do, I'm currently not sure what the problem is 😅

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the trouble!! Have pushed the updated code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to let you know that I haven't forgotten about this, will take a look as soon as I can


class PlateWeights extends ChangeNotifier{
String unitOfPlate = 'kg';
bool flag = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this do? Probably needs a better name ;)

} else {
selectedWeights.add(x);
}
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't the if and else branches the same? :D

In this respect, I think the different variables could be simplified, e.g.having always totalWeight and totalWeightKg seems redundant.

return Consumer<PlateWeights> (
builder:(context,plateProvider,child)=> Scaffold (
appBar: AppBar (
title: const Text('Enter Custom Plate Weights'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps "Select available plates" would be better. Also, all user-facing strings should be translatable (this also applies for the buttons below, for those there should be already strings).

For this, just add the string to app_en.arb and then you can just use them with AppLocalizations.of(context).<yourKey>; (sometimes the IDE gets a bit confused or doesn't catch up immediately and you'll have to insert the import manually or it will mark the key as not existing, even if it does)

SingleChildScrollView (
scrollDirection: Axis.horizontal,
child: Row (
children: plateProvider.unitOfPlate == 'kg'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both branches are basically the same, you can just do plateProvider.unitOfPlate == 'kg' ? '$number kg' : '$number lbs' within the Text widget

padding: const EdgeInsets.all(16),
decoration: BoxDecoration (
color: plateProvider.selectedWeights.contains(number)
? const Color.fromARGB(255, 82, 226, 236)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of hard coding a color, I would use something from the Theme, then this will also automatically work on the dark mode. There should be something in Theme.of(context).colorScheme suitable for this

import 'package:wger/helpers/gym_mode.dart';

class PlateWeights extends ChangeNotifier{
String unitOfPlate = 'kg';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a boolean would be better here, something like isMetric, then we don't have to use magic strings in the code, which will avoid mistakes like e.g. writing "Lb"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants