unit frmMainMenu_u;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, DateUtils, ExtCtrls, dmFitness_u, Grids, DBGrids,
Math,DB,
//forms
frmWorkouts_u,
frmUserProfile_u,
frmSports_u,
frmProgress_u,
frmNutrition_u;
type
TfrmMainMenu = class(TForm)
procedure FormShow(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormResize(Sender: TObject);
private
lblTitle, lblWelcome : TLabel;
arrNavButtons : array of TButton;
arrPnlCards : array of TPanel;
arrCardPaintBoxes : array of TPaintBox;
arrLblCardValue : array of TLabel;
arrCardTarget : array of Integer; //animated goal perc 0..100
arrCardCurrent : array of Integer;//animated current perc
TimerFade : TTimer;
TimerSlide : TTimer;
TimerRing : TTimer;
iAnimStep : integer;
iCurrUserID : integer;
pnlCenter : TPanel;
pnlRight : TPanel;
pnlLeft : TPanel;
bFlag : boolean;
//shortcut buttons
btnQuickWorkout : TButton;
btnQuickMeal : TButton;
btnQuickWeighIn : TButton;
lblCalToday : TLabel;
lblWorkoutsWeek : TLabel;
lblSportsMonth : TLabel;
memRecent : TMemo;
procedure FormClose(Sender : TObject; var Action: TCloseAction);
procedure OnNavButtonClick(Sender : TObject);
procedure OnNavButtonMouseEnter(Sender : TObject);
procedure OnNavButtonMouseLeave(Sender : TObject);
procedure OnPaintBoxPaint(Sender : TObject);
procedure TimerFadeTick(Sender : TObject);
procedure TimerSlideTick(Sender : TObject);
procedure TimerRingTick(Sender : TObject);
//Helping procedure/Functions
procedure CreateDynamicUI;
procedure StartEntryAnim;
procedure SetupCardTargets; //read DB set CardTarget
function CountWorkoutLast7Days (UserID : Integer): Integer;
function CaloriesToday (UserID: Integer): Integer;
function SportThsMonth (UserID: Integer) : Integer;
procedure CreateCenterPanel;
procedure CreateQuickActions;
procedure CreateSnapshotLabels;
procedure CreateRecentActivity;
procedure RefreshDashboard;
procedure PositionCenterControls;
procedure QuickActionClick(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
{ Private declarations }
public
constructor Create(AOwner : TComponent); override;
procedure SetCurrentUser(UserID: Integer);
{ Public declarations }
end;
var
frmMainMenu: TfrmMainMenu;
const
arrNavCaptions : array [0..5] of string = (
'Workouts',
'Nutrition',
'Sports',
'Progress',
'Profile',
'Log out'
);
implementation
{$R *.dfm}
{-------------- Helper: DB aclculations --------------}
function [Link](UserID: Integer): Integer;
var
iPosMealSaved, iPosMealSavedItems, iPosFoodsSaved : integer;
iMealID : integer;
dtToday : TDateTime;
rQuantity : Double;
rFoodCalories : Double;
begin
Result := 0;
if NOT Assigned(dmFitness) then
begin
Exit;
end;
dtToday := Date;
//Each meal for user today, calc sum calories
with dmFitness do
begin
[Link];
[Link];
try
[Link];
while NOT [Link] do
begin
if (tblMeals['UserID'] = UserID) AND
(Trunc(tblMeals['MealDate']) = Trunc(dtToday)) then
begin
iMealID := tblMeals['MealID'];
with dmFitness do
begin
[Link];
while NOT [Link] do
begin
if tblMealItems['MealID'] = iMealID then
begin
rQuantity := tblMealItems['Quantity'];
//Find food row
with dmFitness do
begin
if [Link]('FoodID',tblFoods['FoodID'],[]) then
begin
rFoodCalories := tblFoods['Calories'];
Result := Result + Round(rFoodCalories* rQuantity)
end;//end if
end;//end with foods
end;// end if
[Link];
end;
end;
end;
[Link];
end;
finally
[Link]
end;
end;
end;
function TfrmMainMenu.CountWorkoutLast7Days(UserID : integer): integer;
var
iSavedPos : integer;
SevenDayDate : TDateTime;
begin
Result := 0;
with dmFitness do
begin
if NOT [Link] then
[Link];
if NOT Assigned(dmFitness) then
Exit;
SevenDayDate := Date - 7;
with dmFitness do
begin
[Link];
try
iSavedPos := [Link];
[Link];
while NOT [Link] do
begin
if (tblWorkouts['UserID'] = UserID) AND (tblWorkouts['WorkoutDate']
>= SevenDayDate)then
Inc(Result);
[Link];
end;//end with
//Restore pos if possible
if [Link] > 0 then
[Link];
finally
[Link];
end;//end try
end;//end with
end;
end;
constructor [Link](AOwner: TComponent);
begin
inherited Create(AOwner);
//Call SetCurrentUser after login
iCurrUserID := -1;
//form Properties for fade anim
with Self do
begin
BorderStyle := bsSizeable;
Position := poScreenCenter;
Caption := 'Fitness App - Dashboard';
end;
//When closed
OnClose := FormClose;
end;
procedure [Link];
begin
// center panel
if Assigned(pnlCenter) AND Assigned(pnlRight) AND Assigned(pnlLeft) then
Exit;
if NOT Assigned(pnlLeft) then
begin
pnlLeft := [Link](Self);
[Link] := Self;
[Link] := bvNone;
[Link] := '';
[Link] := clBtnFace;
[Link] := True;
end;
if NOT Assigned(pnlRight) then
begin
pnlRight := [Link](Self);
[Link] := Self;
[Link] := bvNone;
[Link] := '';
[Link] := clBtnFace;
[Link] := True; // reduce flicker
end;
if NOT Assigned(pnlCenter) then
begin
pnlCenter := [Link](Self);
[Link] := Self;
[Link] := alNone;
[Link] := bvNone;
[Link] := '';
[Link] := clWhite;
[Link] := bsNone;
end;
[Link] := alNone
;
[Link] := 180;
[Link] := alNone;
[Link] := 280;
CreateQuickActions;
CreateSnapshotLabels;
CreateRecentActivity;
[Link] := 100;
[Link] := True;
[Link] := FormKeyDown;
end;
procedure [Link];
var
i : integer;
btn : TButton;
pnlCard : TPanel;
paintbx : TPaintBox;
lblval : TLabel;
iContainerTop : integer;
begin
//Title label
lblTitle := [Link](Self);
with lblTitle do
begin
Parent := Self;
Caption := 'Framesby Fitness Program';
[Link] := 24;
[Link] := [fsBold];
Left := -800;
Top := 20;
AutoSize := True;
end;
//Welcome Label
lblWelcome := [Link](Self);
with lblWelcome do
begin
Parent := Self;
Caption := 'Welcome!';
[Link] := 14;
Left := [Link] + 200;
Top := 60;
AutoSize := True;
end;
//Navigation buttons
//arrNavCaptions := ['Workouts','Nutrition','Sports','Progress','Profile','Log out'];
SetLength(arrNavButtons,length(arrNavCaptions));
for i := 0 to High(arrNavButtons) do
begin
btn := [Link](Self);
with btn do
begin
Parent := pnlLeft;;
Caption := arrNavCaptions[i];
Width := 140;
Height := 42;
Left := 20;
Top := 20 + (i * 10);// off screen bottom start
Tag := i;
Hint := 'Open ' + arrNavCaptions[i];
ShowHint := True;
OnClick := OnNavButtonClick;
OnMouseEnter := OnNavButtonMouseEnter;
OnMouseLeave := OnNavButtonMouseLeave;
SetLength(arrNavButtons,length(arrNavButtons));//prevent stable
issues;
arrNavButtons[i] := btn;
end;
end;
//summary cards on top right area
SetLength(arrPnlCards,3);
SetLength(arrCardPaintBoxes,3);
SetLength(arrCardTarget,3);
SetLength(arrCardCurrent,3);
SetLength(arrLblCardValue,3);
iContainerTop := 120;
for i := 0 to 2 do
begin
pnlCard := [Link](Self);
with pnlCard do
begin
Parent := pnlRight;
Width := 240;
Height := 120;
BevelInner := bvNone;
BevelOuter := bvRaised;
Caption := '';
end;//end with pnlcard
//Rings(paintbox)
paintbx := [Link](Self);
with paintbx do
begin
Parent := pnlCard;
Align := alLeft;
Width := 120;
Height := [Link];
OnPaint := OnPaintBoxPaint;
Tag := i;//index
end;
//Numeric value label to the right
lblval := [Link](Self);
with lblval do
begin
Parent := pnlCard;
Left := [Link] + 16;
Top := 24;
Caption := '...';
[Link] := 12;
end;
//store
arrPnlCards[i] := pnlCard;
arrCardPaintBoxes[i] := paintbx;
arrLblCardValue[i] := lblval;
arrCardTarget[i] := 0;
arrCardCurrent[i] := 0;
end;
//Set TabOrder for accessibility
for i := 0 to High(arrNavButtons) do
arrNavButtons[i].TabOrder := i;
//show hints
[Link] := True;
end;
procedure [Link];
const
btnHeight = 38;
btnWidth = 140;
var
iLeftX, iTopY, iGap : integer;
begin
//Create buttons
btnQuickWorkout := [Link](Self);
btnQuickMeal := [Link](Self);
btnQuickWeighIn := [Link](Self);
with btnQuickWorkout do
begin
Parent := pnlCenter;
Caption := 'Log & workout';
[Link] := bvNone;
[Link] := '';
Width := btnWidth;
Height := btnHeight;
Hint := 'Ctrl+W';
ShowHint := True;
OnClick := QuickActionClick;
end;
with btnQuickMeal do
begin
Parent := pnlCenter;
Caption := 'Log & meal';
[Link] := bvNone;
[Link] := '';
Width := btnWidth;
Height := btnHeight;
Hint := 'Ctrl+N';
ShowHint := True;
OnClick := QuickActionClick;
end;
with btnQuickWeighIn do
begin
Parent := pnlCenter;
Caption := 'Quick Weigh-in';
Width := btnWidth;
Height := btnHeight;
Hint := 'Ctrl+G';
ShowHint := True;
OnClick := QuickActionClick;
end;
iGap := 20;
iLeftX := ([Link] DIV 2) - ([Link] DIV 2);
iTopY := 40;
[Link](iLeftX, iTopY, [Link],
[Link]);
[Link](iLeftX, iTopY + [Link] + iGap,
[Link], [Link]);
[Link](iLeftX, iTopY + ([Link] + iGap) *
2,
[Link], [Link]);
end;
procedure [Link];
begin
memRecent := [Link](Self);
with memRecent do
begin
Parent := pnlCenter;
ReadOnly := True;
ScrollBars := ssVertical;
WordWrap := False;
[Link] := 'Segoe UI';
[Link]('Recent activity will show here...');
end;
end;
procedure [Link];
var
lbl : TLabel;
begin
//Calories today
lblCalToday := [Link](Self);
with lblCalToday do
begin
Parent := pnlCenter;
[Link] := 12;
Caption := 'Calories today: 0 kcal';
end;
//Workouts this week
lblWorkoutsWeek := [Link](Self);
with lblWorkoutsWeek do
begin
Parent := pnlCenter;
[Link] := 12;
Caption := 'Workouts (7d): 0';
end;
//Sport sessions this month
lblSportsMonth := [Link](Self);
with lblSportsMonth do
begin
Parent := pnlCenter;
[Link] := 12;
Caption := 'Sports sessions (month): 0';
end;
end;
procedure [Link](Sender: TObject; var Action: TCloseAction);
begin
//Stop timers
[Link] := False;
[Link] := False;
[Link] := False;
end;
procedure [Link](Sender: TObject);
begin
bFlag := False;
if NOT Assigned(dmFitness) then
dmFitness := [Link](Self);
//open all tables to ensure working
with dmFitness do
begin
if NOT [Link] then [Link];
if NOT [Link] then [Link];
if NOT [Link] then [Link];
if NOT [Link] then [Link];
if NOT [Link] then [Link];
if NOT [Link] then [Link];
if NOT [Link] then [Link];
if NOT [Link] then [Link];
end;
end;
procedure [Link](Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
//shortcut keys
if (ssCtrl IN Shift ) then
begin
case Key of
Ord('W'): [Link]; // Ctrl+W
Ord('N'): [Link]; // Ctrl+N
Ord('G'): [Link]; // Ctrl+G
Ord('P'): if Assigned(frmProfile) then
[Link]; // ctrl+P
end;
end;
end;
procedure [Link](Sender: TObject);
var
i : integer;
begin
if bFlag then
Exit;
bFlag := True;
try
PositionCenterControls;
finally
bFlag := False;
end;
for i := 0 to High(arrCardPaintBoxes) do
if Assigned(arrCardPaintBoxes[i]) then
arrCardPaintBoxes[i].Invalidate;
end;
procedure [Link](Sender: TObject);
begin
if NOT bFlag then
begin
//Timers
TimerFade := [Link](Self);
[Link] := 20;
[Link] := TimerFadeTick;
TimerSlide := [Link](Self);
[Link] := 18;
[Link] := TimerSlideTick;
TimerRing := [Link](Self);
[Link] := 20;
[Link] := TimerRingTick;
//start of fade
with dmFitness do
begin
if NOT [Link] then
[Link];
[Link];
[Link] := 'Welcome, ' + tblUsers['FullName'];
end;
bFlag := True;
CreateCenterPanel;
CreateDynamicUI;
PositionCenterControls;
RefreshDashboard;
StartEntryAnim;
end;
end;
procedure [Link](Sender: TObject);
var
iIndex : integer;
begin
iIndex := (Sender as TButton).Tag;
case iIndex of
0 : ShowMessage('Open Workouts form (implement)');
1 : ShowMessage('Open Nutrition / Meals form (implement)');
2 : ShowMessage('Open Sports Sessions form (implement)');
3 : ShowMessage('Open Progress form (implement)');
4 : ShowMessage('Open Profile form (implement)');
5 : Close; // logout/exit
end;
end;
procedure [Link](Sender: TObject);
var
B : TButton;
begin
//(Sender as TButton).[Link] := [];
//(Sender as TButton).Color := clBtnFace;
if NOT (Sender is TButton) then
Exit;
B := TButton(Sender);
[Link] := [Link] + [fsBold];
[Link] := RGB(0, 102, 204);
[Link] := [Link] + 6;
end;
procedure [Link](Sender: TObject);
var
B : TButton;
begin
//(Sender as TButton).[Link] := [fsBold];
//(Sender as TButton).Color := RGB(230,245,255);
if NOT (Sender is TButton) then Exit;
B := TButton(Sender);
[Link] := [Link] - [fsBold];
[Link] := clBtnText;
[Link] := [Link] - 6;
end;
procedure [Link](Sender: TObject);
var
PB : TPaintBox;
iIndex : integer;
R, rect : TRect;
iCx, iCy, ir, iPenWidth: integer;
rStartAngle, rEndAngle : Double;
iXStart, iYStart, iXEnd, iYEnd : integer;
BackupPen : TPen;
BackupBrush : TBrush;
iProgress : integer;
lblTxt : string;
iFSize : integer;
begin
PB := Sender AS TPaintBox;
iIndex := [Link];
R := [Link];
//center and raduis based on pb size
iCx := ([Link] - [Link]) DIV 2;
iCy := ([Link] - [Link]) DIV 2;
ir := Min(iCx,iCy) - 10;
iPenWidth := Max(6, Round(ir * 0.14));
if iPenWidth > Round(ir /2) then
iPenWidth := Round(ir / 2);
//Current anim percent
iProgress := 0;
if (iIndex >= 0) AND (iIndex <= High(arrCardCurrent)) then
iProgress := arrCardCurrent[iIndex];
//clear
[Link] := [Link];;
[Link](R);
//Background Ring;
BackupPen := [Link];
BackupBrush := [Link];
try
[Link]([Link]);
[Link]([Link]);
[Link] := iPenWidth;
[Link] := RGB(230,230,230);
[Link] := bsClear;
//Draw full circle
[Link](iCx - ir, iCy - ir, iCx + ir, iCy + ir);
//Draw progress arc at - 90 degrees
rStartAngle := -90;
rEndAngle := rStartAngle + (iProgress/100) * 360;
//Give arc endpoints
iXStart := Round(iCx + ir * Cos(DegToRad(rStartAngle)));
iYStart := Round(iCy + ir * Sin(DegToRad(rStartAngle)));
iXEnd := Round(iCx + ir * Cos(DegToRad(rEndAngle)));
iYEnd := Round(iCy + ir * Sin(DegToRad(rEndAngle)));
[Link] := RGB(60,160,220);
[Link] := iPenWidth;
//Arc draws outline por of circle
[Link](iCx - ir, iCy - ir, iCx + ir, iCy + ir,iXStart, iYStart,iXEnd,iYEnd);
//Center for text
iFSize := Max(8, Round(ir * 0.28));
[Link] := iFSize;
[Link] := [fsBold];
lblTxt := IntToStr(iProgress) + '%';
[Link](iCx - [Link](lblTxt) DIV 2,
iCy - [Link](lblTxt) DIV 2, lblTxt);
finally
[Link](BackupPen);
[Link](BackupBrush);
[Link];
[Link];
end;
end;
procedure [Link];
var
iLeftWidth, iRightWidth, iGap, iTopMargin, iCenterLeft, iCenterWidth: Integer;
ibtnTop, ibtnLeft, ibtnGap: Integer;
i, iYPos, iCardWidth : integer;
pnlCard : TPanel;
pb : TPaintBox;
const
iCardHeight = 120;
iCardGap = 12;
begin
if bFlag then
Exit;
bFlag := True;
try
if (pnlCenter = nil) OR (pnlRight = nil) then
begin
Exit;
end;
if NOT Assigned(pnlCenter) OR NOT Assigned(pnlRight) then
Exit;
iGap := 20;
iTopMargin := 100;
//set left and right columm widths to match nav layout
iLeftWidth := Max(160, Round(ClientWidth * 0.17)); // left nav
iRightWidth := Max(260, Round(ClientWidth * 0.28)); // right rings
iCenterLeft := iLeftWidth + iGap;
iCenterWidth := ClientWidth - iLeftWidth - iRightWidth - (iGap * 3);
if iCenterWidth < 300 then
iCenterWidth := 300;
// temporarily disable align to prevent resize
[Link] := alNone;
[Link] := alNone;
//Centre panel postition
[Link](iCenterLeft, iTopMargin, iCenterWidth, ClientHeight -
iTopMargin - 40);
//right panel position
[Link](iCenterLeft + iCenterWidth + iGap, iTopMargin, iRightWidth,
ClientHeight - iTopMargin - 40);
//layout of cards inside pnlright
iCardWidth := [Link] - 20;
iYPos := 8;
for i := 0 to High(arrPnlCards) do
begin
if NOT Assigned(pnlCard) then
Continue;
with pnlCard do
begin
Parent := pnlRight;
Width := iCardWidth;
Height := iCardHeight;
Left := 10;
Top := iYPos;
end;
//Resize the paintbox inside pnl
pb := arrCardPaintBoxes[i];
if Assigned(pb) then
begin
[Link] := pnlCard;
[Link] := Round([Link] * 0.45) ;
[Link] := [Link] - 10;
[Link] := 6;
[Link] := ([Link] - [Link]) DIV 2;
end;
//position value labels next pb
if Assigned(arrLblCardValue[i]) then
begin
arrLblCardValue[i].Parent := pnlCard;
arrLblCardValue[i].Left := [Link] + [Link] + 12;
arrLblCardValue[i].Top := ([Link] -
arrLblCardValue[i].Height) DIV 2;
end;
Inc(iYPos, iCardHeight + iCardGap);
end;
//Invalidate pb to redraw new size
for i := 0 to High(arrCardPaintBoxes) do
if Assigned(arrCardPaintBoxes[i]) then
arrCardPaintBoxes[i].Invalidate;
//quick actions btns top of pnlcenter
ibtnGap := 14;
ibtnLeft := ([Link] - ([Link] * 3 + ibtnGap *
2)) div 2;
ibtnTop := 12;
[Link] := ibtnLeft;
[Link] := ibtnTop;
[Link] := [Link] + [Link] +
ibtnGap;
[Link] := ibtnTop;
[Link] := [Link] + [Link] + ibtnGap;
[Link] := ibtnTop;
//Labels under quick actions
[Link] := 12;
[Link] := ibtnTop + [Link] + 12;
[Link] := 12;
[Link] := [Link] + 22;
[Link] := 12;
[Link] := [Link] + 22;
//Recent activity memo
[Link] := 12;
[Link] := [Link] + 28;
[Link] := [Link] - 24;
[Link] := [Link] - [Link] - 12;
finally
bFlag := False;
end;
end;
procedure [Link](Sender: TObject);
begin
if Sender = btnQuickWorkout then
begin
//open workouts form
if NOT Assigned(frmWorkouts) then
frmWorkouts := [Link](Application);
[Link];
end
else
if Sender = btnQuickMeal then
begin
if NOT Assigned(frmNutrition) then
frmNutrition := [Link](Application);
[Link];
end
else
if Sender = btnQuickWeighIn then
begin
if NOT Assigned(frmProgress) then
frmProgress := [Link](Application);
[Link];
end;
RefreshDashboard;
end;
procedure [Link];
var
iWkCount, iCalToday, iSportCount: Integer;
iSavedPos: Integer;
sLine: string;
iMaxLines: Integer;
begin
if NOT Assigned(dmFitness) then
Exit;
//safety check
with dmFitness do
begin
if NOT [Link] then
[Link];
if NOT [Link] then
[Link];
if NOT [Link] then
[Link];
if NOT [Link] then
[Link];
if NOT [Link] then
[Link];
if NOT [Link] then
[Link];
//get numeric
iWkCount := 0;
[Link];
try
[Link];
while NOT [Link] do
begin
if ([Link]('UserID').AsInteger = iCurrUserID) AND
([Link]('WorkoutDate').AsDateTime >= Date - 7)
then
Inc(iWkCount);
[Link];
end;
finally
[Link];
end;
//calories today
iCalToday := 0;
[Link];
try
[Link];
while NOT [Link] do
begin
if ([Link]('UserID').AsInteger = iCurrUserID) AND
(Trunc([Link]('MealDate').AsDateTime) =
Trunc(Date))then
begin
[Link];
while NOT [Link] do
begin
if [Link]('MealID').AsInteger =
[Link]('MealID').AsInteger then
begin
//Find calories
if [Link]('FoodID',
[Link]('FoodID').AsInteger,[]) then
begin
iCalToday := iCalToday +
Round([Link]('Calories').AsFloat*
[Link]('Quantity').AsFloat);
end;
end;
[Link];
end;
end;
[Link];
end;
finally
[Link];
end;
//sport this month
iSportCount := 0;
[Link];
try
[Link];
while NOT [Link] do
begin
if ([Link]('UserID').AsInteger = iCurrUserID) AND
(MonthOf([Link]('SessionDate').AsDateTime) =
MonthOf(Date)) then
begin
Inc(iSportCount);
end;
[Link];
end;
finally
[Link];
end;
//add recent activity in memo(last 8 workouts + meals)
[Link];
try
[Link];
iMaxLines := 8;
//Decending date - recent workouts
[Link];
try
[Link];
while NOT [Link] do
begin
if [Link]('UserID').AsInteger = iCurrUserID then
begin
sLine := Format('%s | %s | %s',
[DateToStr([Link]('WorkoutDate').AsDateTime),
[Link]('WorkoutType').AsString,
[Link]('Notes').AsString]);
[Link](sLine);
if [Link] >= iMaxLines then
Break;
end;
[Link];
end;
finally
[Link];
end;
finally
[Link];
end;
end;//end with
end;
procedure [Link](UserID: Integer);
begin
iCurrUserID := UserID;
//Update welcome label
if Assigned(dmFitness) then
begin
if [Link]('UserID',UserID,[]) then
[Link] := 'Welcome, ' +
[Link]('FullName').AsString;
end;
end;
procedure [Link];
var
iCountWorkouts, iCalToday, iSportSesCount : integer;
// convert raw numbers to simple % goals for demo:
// - workouts: 0..7 => % of 4 workouts/week target
// - calories: compute percent of 2500 kcal daily goal
// - sports: count in month vs 8 sessions target
begin
if iCurrUserID < 0 then
begin
//Try use first user in table
if Assigned(dmFitness) AND ([Link] > 0)then
[Link];
if Assigned(dmFitness) AND (NOT [Link])then
iCurrUserID := [Link]('UserID').AsInteger;
end;
if NOT [Link] then
[Link];
//assign valuse
iCountWorkouts := CountWorkoutLast7Days(iCurrUserID);
iCalToday := CaloriesToday(iCurrUserID);
iSportSesCount := SportThsMonth(iCurrUserID);
arrCardTarget[0] := Min(100, Round((iCountWorkouts/4)*100)); //Target 4
workouts per week
arrCardTarget[1] := Min(100, Round((iCalToday/2500)*100)); //Daily cal goal;
arrCardTarget[2] := Min(100, Round((iSportSesCount/8)*100)); //Monthly target
= 8 ses;
arrLblCardValue[0].Caption := IntToStr(iCountWorkouts) + ' wk';
arrLblCardValue[1].Caption := IntToStr(iCalToday) + ' kcal';
arrLblCardValue[2].Caption := IntToStr(iSportSesCount) + ' mo';
end;
function [Link](UserID: Integer): Integer;
var
dtStartOfMonth : TDateTime;
begin
Result := 0;
if NOT Assigned(dmFitness) then
Exit;
//Count sessions for the current month
dtStartOfMonth := EncodeDate(YearOf(Date), MonthOf(Date),1);
with dmFitness do
begin
[Link];
[Link];
try
[Link];
while NOT [Link] do
begin
if (tblSportSessions['UserID'] = UserID) AND
(tblSportSessions['SessionDate'] >= dtStartOfMonth) then
begin
Inc(Result);
end;
[Link];
end;// end with eof
finally
[Link];
end;// end try
end; //end with dm
end;
procedure [Link];
begin
//Initial state
[Link] := True;
[Link] := 0;
iAnimStep := 0;
[Link] := True;
end;
procedure [Link](Sender: TObject);
begin
if [Link] < 255 then
[Link] := Min(255, [Link] + 20)
else
begin
[Link] := False;
//start animation for title/welcome/Nav
[Link] := True;
end;
end;
procedure [Link](Sender: TObject);
var
i : integer;
bsChanged : boolean;
begin
bsChanged := False;
for i := 0 to High(arrCardCurrent) do
begin
if arrCardCurrent[i] < arrCardTarget[i] then
begin
Inc(arrCardCurrent[i],Max(1, Round((arrCardTarget[i] -
arrCardCurrent[i])/8)));
if arrCardCurrent[i] > arrCardTarget[i] then
arrCardCurrent[i] := arrCardTarget[i];
bsChanged := True;
//Update display
arrLblCardValue[i].Caption := IntToStr(Round(arrCardCurrent[i])) + '%';
arrCardPaintBoxes[i].Invalidate;
end;
end;
//if anim finished
if NOT bsChanged then
[Link] := False
end;
procedure [Link](Sender: TObject);
var
i : integer;
iTargetDrop : integer;
bsFinished : boolean;
begin
//slide from left to x = 30 (Title label)
if [Link] < 30 then
[Link] := [Link] + 22;
//Slide from right to x = 320 (welcome lbl)
if [Link] > ([Link] DIV 3) then
[Link] := [Link] - 20;
//Slide navigation buttons into position
//top starts at 150 + i*
bsFinished := True;
for i := 0 to High(arrNavButtons) do
begin
iTargetDrop := 150 + i * 58;
if arrNavButtons[i].Top > iTargetDrop then
begin
arrNavButtons[i].Top := arrNavButtons[i].Top - 18;
bsFinished := False;
end;
end;
//When slide done - stop and start ring animation after DB targets
if bsFinished AND ([Link] >= 30) AND ([Link] <=
([Link] DIV 3)) then
begin
[Link] := False;
SetupCardTargets;
//start ring anim and counters
[Link] := True;
end;
end;
end.