diff --git a/doc/page-customize.png b/doc/page-customize.png new file mode 100644 index 0000000000000000000000000000000000000000..a8d8c1c5b83de93bd1116ac8b6c936f67e37b14e Binary files /dev/null and b/doc/page-customize.png differ diff --git a/doc/page-dashboard.png b/doc/page-dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..265d61aab771131932fce753c9774df368af0945 Binary files /dev/null and b/doc/page-dashboard.png differ diff --git a/doc/page-end of exercise.png b/doc/page-end of exercise.png new file mode 100644 index 0000000000000000000000000000000000000000..d8bbc5651432686b301607f6ea9f1f6300e58395 Binary files /dev/null and b/doc/page-end of exercise.png differ diff --git a/doc/page-exercise.png b/doc/page-exercise.png new file mode 100644 index 0000000000000000000000000000000000000000..3f01f480a83d943be71b4e418a0d37e56bd365a4 Binary files /dev/null and b/doc/page-exercise.png differ diff --git a/doc/page-list.png b/doc/page-list.png new file mode 100644 index 0000000000000000000000000000000000000000..53e29ea1e8b8108100fe5f6c39940d22e3e0ad70 Binary files /dev/null and b/doc/page-list.png differ diff --git a/doc/page-plan.png b/doc/page-plan.png new file mode 100644 index 0000000000000000000000000000000000000000..e57f771ff88f57de5135a010a3df51eb175ec7a3 Binary files /dev/null and b/doc/page-plan.png differ diff --git a/doc/page-register.png b/doc/page-register.png new file mode 100644 index 0000000000000000000000000000000000000000..a7dc8a3c90c3f5e17bba7fa6e772da3f0e322d94 Binary files /dev/null and b/doc/page-register.png differ diff --git a/img/exe-bearcrawl.gif b/img/exe-bearcrawl.gif new file mode 100644 index 0000000000000000000000000000000000000000..3f8773df67d8c370cbe934283e9b2a6c1fd7415d Binary files /dev/null and b/img/exe-bearcrawl.gif differ diff --git a/img/exe-hipdip.gif b/img/exe-hipdip.gif new file mode 100644 index 0000000000000000000000000000000000000000..678931334f0f5dd3f732904e7c492b610b2a478e Binary files /dev/null and b/img/exe-hipdip.gif differ diff --git a/img/exe-shouldertap.gif b/img/exe-shouldertap.gif new file mode 100644 index 0000000000000000000000000000000000000000..6623a22fbaa43936d41faf5f382efff878780064 Binary files /dev/null and b/img/exe-shouldertap.gif differ diff --git a/img/exe-toetap.gif b/img/exe-toetap.gif new file mode 100644 index 0000000000000000000000000000000000000000..bc161f240737152609ef3fee27bd0fc76a1ffdf1 Binary files /dev/null and b/img/exe-toetap.gif differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8f1d783af96fc182c27706439da1fe021feb3527 Binary files /dev/null and b/img/logo.png differ diff --git a/src/controller.py b/src/controller.py new file mode 100644 index 0000000000000000000000000000000000000000..bec3560578d6ecebc6f35857a56ccdf7e8af5d99 --- /dev/null +++ b/src/controller.py @@ -0,0 +1,243 @@ +from PyQt6.QtWidgets import QApplication +import sys +import sqlite3 +from register import register +from dashboard import dashboard +from listlatihan2 import listLatihan2 +from customize import customizeWorkout +from plan import plan +from plan2 import plan2 +from endOfExercise import endOfExe +import os +import os.path +class controller: + def __init__(self): + self.initDatabase() + self.conn = sqlite3.connect('fitu.db') + self.registerWin = register() + self.registerWin.switch.connect(self.fromRegister) + self.dashboard = dashboard() + self.dashboard.switch.connect(self.fromDashboard) + self.listLatihan = listLatihan2() + self.listLatihan.switch.connect(self.fromListLatihan) + self.customize = customizeWorkout(0) + self.customize.switch.connect(self.fromCustomize) + self.plan = plan() + self.plan.switch.connect(self.fromPlan) + self.plan2 = plan2(1) + self.plan2.switch.connect(self.fromPlan2) + # self.plan2.switch.connect(self.toDashboard) + self.endOfExe = endOfExe() + # self.endOfExe.switch.connect(self.toEndOfExe) + self.endOfExe.switch.connect(self.fromEndOfExe) + pass + + + def start(self): + c = self.conn.cursor() + c.execute("SELECT * FROM user") + count = c.fetchone() + if (count != None): + self.dashboard.show() + else: + self.registerWin.show() + + def fromRegister(self): + self.registerWin.close() + self.dashboard = dashboard() + self.dashboard.switch.connect(self.fromDashboard) + self.dashboard.show() + + def fromDashboard(self, page, program_id): + self.registerWin.close() + self.dashboard.close() + if (page == "listLatihan"): + self.listLatihan.show() + elif (page == "customize"): + self.customize.show() + elif (page == "plan"): + self.plan.show() + + + def fromListLatihan(self, page, program_id): + self.listLatihan.close() + if (page == "dashboard"): + self.dashboard.show() + elif (page == "customize"): + self.customize.show() + elif (page == "plan"): + self.plan.show() + + def fromPlan(self, page, program_id): + self.plan.close() + if (page == "dashboard"): + self.dashboard.show() + elif (page == "customize"): + self.customize = customizeWorkout(program_id) + self.customize.switch.connect(self.fromCustomize) + self.customize.show() + elif (page == "listLatihan"): + self.listLatihan.show() + elif (page == "plan2"): + self.plan2 = plan2(program_id) + self.plan2.switch.connect(self.fromPlan2) + self.plan2.show() + + def fromCustomize(self, page, program_id): + self.customize.close() + if (page == "dashboard"): + self.dashboard.show() + elif (page == "listLatihan"): + self.listLatihan.show() + elif (page == "plan"): + self.plan = plan() + self.plan.switch.connect(self.fromPlan) + self.plan.show() + + + def fromPlan2(self,page): + self.plan2.close() + if (page == "endOfExe"): + self.endOfExe.show() + elif (page == "plan"): + self.plan.show() + + def fromEndOfExe(self,page): + self.endOfExe.close() + if (page == "dashboard"): + self.dashboard = dashboard() + self.dashboard.switch.connect(self.fromDashboard) + self.dashboard.show() + + def initDatabase(self): + if not os.path.exists("fitu.db"): + self.con = sqlite3.connect("fitu.db") + cur = self.con.cursor() + + cur.execute(""" + CREATE TABLE IF NOT EXISTS user ( + name text PRIMARY KEY, + height integer, + weight integer, + goal text, + gender text, + age integer + ) + """) + cur.execute(""" + CREATE TABLE IF NOT EXISTS daftar_latihan ( + exercise_id integer PRIMARY KEY, + title text, + description text, + goals text, + duration integer, + repetition integer, + gif text + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS riwayat_latihan ( + history_id integer, + program_id integer, + name text, + title_program text, + calories integer, + date text, + tot_duration integer, + FOREIGN KEY (program_id) REFERENCES program (program_id) + ) + """) + cur.execute(""" + CREATE TABLE IF NOT EXISTS program ( + program_id integer PRIMARY KEY AUTOINCREMENT, + title_program text + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS latihan_program ( + program_id integer, + exercise_id integer, + FOREIGN KEY (program_id) REFERENCES program (program_id) + ) + """) + + cur.execute(""" + INSERT or IGNORE INTO daftar_latihan + (exercise_id, title, description, goals, duration, repetition, gif) + VALUES + (101, "Hip Dip", "The hip dip exercise is performed by placing your forearms on the ground with your elbows bent at a 90-degree angle, and then raising your hips off the ground, keeping your feet and forearms on the ground. This exercise targets the oblique muscles and helps to tone and strengthen them.", 'Thin, Fit', 30, NULL, "img/exe-hipdip.gif"), + (102, "Bear Crawl", "The bear crawl exercise is performed by getting into a push-up position and then crawling forward on your hands and feet, keeping your back flat and your core engaged. This exercise targets multiple muscle groups including the shoulders, chest, triceps, and core.", 'Thin, Fit', 30, NULL, "img/exe-bearcrawl.gif"), + (103, "Jumping Jacks", "Jumping jacks are a simple and effective exercise that involves jumping with your feet spread apart and your arms raised above your head, then returning to a standing position with your arms at your sides. This exercise is a great way to get your heart rate up and work on your cardiovascular fitness.", 'Thin, Fit', 30, NULL, "img/exe-jumpingjack.gif"), + (104, "Plank", "The plank is an isometric exercise that involves holding a push-up position for an extended period of time. This exercise targets the core and helps to improve stability and overall strength.", 'Thin, Fit', 30, NULL, "img/exe-plank.gif"), + (105, "Bridge", "The bridge exercise is performed by lying on your back with your knees bent and your feet flat on the ground. Then, you lift your hips up towards the ceiling, squeezing your glutes at the top of the movement. This exercise targets the glutes and helps to tone and strengthen them.", 'Thin, Fit', 30, NULL, "img/exe-bridges.gif"), + (106, "High Knees", "High knees are performed by running in place while lifting your knees up towards your chest as high as possible. This exercise targets the hip flexors and helps to improve speed, agility, and coordination.", 'Thin, Fit', 30, NULL, "img/exe-highknee.gif"), + (107, "Mt. Climber", "The mountain climber exercise is performed by getting into a push-up position and then bringing one knee up towards your chest, alternating legs in a running motion. This exercise targets the core and helps to improve cardiovascular fitness.", 'Thin, Fit', 30, NULL, "img/exe-mountain.gif"), + (108, "Russian Twist", "The Russian twist exercise is performed by sitting on the ground with your knees bent and your feet flat on the ground. Then, you lean back slightly and twist your torso from side to side, touching the ground with your hands on each side. This exercise targets the oblique muscles and helps to improve core strength.", 'Thin, Fit', 30, NULL,"img/exe-russian.gif"), + (201, 'Push Up', 'The push-up is a classic exercise that involves getting into a plank position with your hands placed slightly wider than shoulder-width apart. Then, you lower your body down towards the ground by bending your elbows and push back up to the starting position. This exercise targets multiple muscle groups including the chest, triceps, and shoulders.','Thin, Fit', NULL, 10, 'img/exe-pushup.gif'), + (202, "Sit Up", "The sit-up is performed by lying on your back with your knees bent and your feet flat on the ground. Then, you lift your upper body up towards your knees by contracting your abs. This exercise targets the abdominal muscles and helps to improve core strength.", 'Thin, Fit', NULL, 10, "img/exe-situp.gif"), + (203, "Toe Tap", "The toe tap exercise is performed by lying on your back with your legs extended towards the ceiling. Then, you lower one leg down towards the ground and tap your toe on the floor before raising it back up to the starting position. This exercise targets the lower abdominal muscles and helps to improve core strength.", 'Thin, Fit', NULL, 10, "img/exe-toetap.gif"), + (204, "Shoulder Tap", "The shoulder tap exercise is performed by getting into a push-up position and then tapping one hand to the opposite shoulder, alternating hands. This exercise targets the core and helps to improve stability and overall strength.", 'Thin, Fit', NULL, 10, "img/exe-shouldertap.gif"), + (205, "Lunges", "Lunges are performed by stepping forward with one foot and bending both knees, lowering your body towards the ground before returning to the starting position. This exercise targets the legs and helps to improve lower body strength.", 'Thin, Fit', NULL, 10, "img/exe-lunges.gif"), + (206, "Crunches", "Crunches are a classic abdominal exercise that target the rectus abdominis muscle (the six-pack muscles) and the obliques. To perform a crunch, lie on your back with your knees bent and feet flat on the ground. Place your hands behind your head or across your chest, and engage your core to lift your shoulders and upper back off the ground. Exhale as you crunch up, and inhale as you lower back down.", 'Thin, Fit', NULL, 10, "img/exe-crunches.gif"), + (207, "Burpees", "Burpees are a full-body exercise that incorporate cardio and strength training. To perform a burpee, start in a standing position, then drop down into a squat and place your hands on the ground. Jump or step your feet back into a plank position, then perform a push-up. Jump or step your feet back up to your hands, then explode up into a jump, reaching your arms overhead. That's one rep", 'Thin, Fit', NULL, 10, "img/exe-burpees.gif"), + (208, "Bicycle Crunch", "The bicycle crunch is a core exercise that targets the rectus abdominis and the obliques. To perform a bicycle crunch, lie on your back with your hands behind your head and your knees bent. Lift your shoulders off the ground and bring your right elbow towards your left knee, while straightening your right leg. Then, switch sides, bringing your left elbow towards your right knee, while straightening your left leg. Continue alternating sides in a pedaling motion.", 'Thin, Fit', NULL, 10, "img/exe-bicycle.gif") + """) + + cur.execute(""" + INSERT or IGNORE INTO program + (program_id, title_program) + VALUES + (1, 'Full Body Workout'), + (2, 'Upper Body Workout'), + (3, 'Lower Body Workout'), + (4, 'Core Workout') + """) + + cur.execute(""" + INSERT or IGNORE INTO latihan_program + (program_id, exercise_id) + VALUES + (1, 201), + (1, 105), + (1, 106), + (1, 202), + (2, 104), + (2, 107), + (2, 108), + (2, 201), + (3, 202), + (3, 205), + (3, 106) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS quotes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + quote TEXT + )""") + + cur.execute(""" + INSERT OR IGNORE INTO quotes + (quote) + VALUES + ('“Strength does not come from\nphysical capacity. It comes from\nan indomitable will.â€\n-Mahatma Gandhi'), + ('“Push harder than yesterday if you\nwant a different tomorrow.â€\n- Unknown'), + ('“Motivation is what gets you\nstarted. Habit is what keeps\nyou going.â€\n-Jim Ryun'), + ('“There are two types of pain in this\nworld: pain that hurts you, and pain\nthat changes you.â€\n- Unknown'), + ('“When you hit failure, your\nworkout has just begun.â€\n-Ronnie Coleman'), + ('“It never gets easier, you just\nget better.â€\n-Unknown'), + ('“Don’t limit your challenges.\nChallenge your limits.â€\n-Jerry Dunn') + + + """) + + self.con.commit() + self.con.close() + +if __name__ == "__main__": + app = QApplication(sys.argv) + controller = controller() + controller.start() + app.exec() diff --git a/src/customize.py b/src/customize.py new file mode 100644 index 0000000000000000000000000000000000000000..9dbd251a933570ca02d40c7dccc5d99d664a114b --- /dev/null +++ b/src/customize.py @@ -0,0 +1,508 @@ +import sqlite3 +import sys + +from PyQt6.QtCore import Qt, QSize, QPropertyAnimation, QAbstractAnimation, QEasingCurve, QAnimationGroup, pyqtSignal +from PyQt6.QtGui import QIcon, QPixmap, QCursor, QFont, QMovie +from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout, + QGroupBox, QRadioButton, QCheckBox, QMessageBox, + QLabel, QLineEdit, QVBoxLayout, QPushButton, QScrollArea, QGraphicsOpacityEffect) + +background = '#5A8D6C' +button_color = '#174728' +text_color = '#EEEEE2' +cardColor = '#D2DCC4' + +class customizeWorkout(QWidget): + switch = pyqtSignal(str, int, dict) + + def __init__(self, program_id): + + super().__init__() + self.con = sqlite3.connect('fitu.db') + self.listEx = self.fetchListEx() + self.program_id = program_id + self.setupGUI() + + def fetchListEx(self): + cur = self.con.cursor() + rows = cur.execute("SELECT * FROM daftar_latihan") + rows = cur.fetchall() + cur.close() + + return rows + + def setupGUI(self): + + self.label = QLabel("") + self.label.setParent(self) + self.setFixedSize(1280, 720) + self.setWindowIcon(QIcon("img/logo.png")) + self.setWindowTitle("FitU - Customize Workout") + self.setStyleSheet("background-color: #5A8D6C;") + self.elements() + + def exLabel(self): + exLabel = QLabel() + + exLabel.setFixedSize(367, 99) + exLabel.setStyleSheet("background-color: #5A8D6C; border-radius: 20px;") + exLabel1 = QLabel(exLabel) + exLabel1.move(10, 10) + exLabel1.setFixedSize(79, 79) + exLabel1.setStyleSheet(f''' + border: none; + "background-color: #D2DCC4;" + "border-radius: 20px;" + + ''') + + def elements(self): + buttonFont = QFont() + buttonFont.setFamily('Segoe UI') + buttonFont.setPointSize(18) + buttonFont.setBold(True) + + #STYLESHEET + styleSheet = ( + "background-color: #D2DCC4;" + "border-radius: 20px;" + ) + styleSheet2 = ( + "color: #5A8D6C;" + "background-color: #D2DCC4;" + "border-radius: 20px;" + ) + + styleSheet3 = ( + "background-color: #5A8D6C;" + "border-radius: 20px;" + ) + + styleSheet4 = ( + "color: #EEEEE2;" + "background-color: #174728;" + "border-radius: 20px;" + f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + }} + ''' + ) + + styleSheet5 = ( + # "color: #D2DCC4;" + "background-color: #D2DCC4;" + "border-radius: 20px;" + ) + # Mengatur bentuk scroll bar + scroll_bar_style = """ + QScrollBar:vertical { + background-color: white; + width: 8px; + margin: 20px 0 20px 0; + } + QScrollBar::handle:vertical { + background-color: #174728; + border-radius: 3px; + + } + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 20px; + background-color: #D2DCC4; + subcontrol-origin: margin; + subcontrol-position: top; + } + QScrollBar::add-line:vertical { + top: 0; + } + QScrollBar::sub-line:vertical { + bottom: 0; + } + """ + #NAVBAR + # masukkan logo + logo = QLabel(self) + logo.setPixmap(QPixmap('img/logo-dashboard.png')) + logo.move(60, 45) + + # tombol home + homeButton = QPushButton(self) + homeButton.setText('Home') + homeButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: {button_color}; + }} + + ''') + homeButton.setFont(buttonFont) + # homeButton.setFixedSize(96, 42) #pake ini buat kalau dia buletan + homeButton.move(670, 58) + homeButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + homeButton.clicked.connect(self.dashboardWindow) + + # tombol customize + customizeButton = QPushButton(self) + customizeButton.setText('Customize') + customizeButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {button_color}; + border: none; + border-radius: 20px; + }} + ''') + customizeButton.setFont(buttonFont) + customizeButton.setFixedSize(140, 42) + customizeButton.move(787, 53) + customizeButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + # customizeButton.clicked.connect(self.customizeWindow) + + # tombol plan + planButton = QPushButton(self) + planButton.setText('Plan') + planButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: {button_color}; + }} + + ''') + planButton.setFont(buttonFont) + planButton.move(956, 58) + planButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + planButton.clicked.connect(self.planWindow) + + # tombol list + listButton = QPushButton(self) + listButton.setText('List') + listButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: {button_color}; + }} + + ''') + listButton.setFont(buttonFont) + listButton.move(1047, 58) + listButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + listButton.clicked.connect(self.listWindow) + + + # foto profil + profilePhoto = QLabel(self) + profilePhoto.setPixmap(QPixmap('img/profile-dashboard.png')) + profilePhoto.move(1133, 45) + + #greenCard + greenCard = QLabel(self) + greenCard.move(116, 155) + greenCard.setFixedSize(430, 534) + greenCard.setStyleSheet(styleSheet) + scroll = QScrollArea(self) + scroll.setWidgetResizable(True) + scroll.setGeometry(130, 250, 410, 429) + scroll.setStyleSheet("background-color: #D2DCC4;border-radius: none;") + scrollWidget = QWidget(scroll) + scrollLayout = QVBoxLayout(scrollWidget) + scrollWidget.setStyleSheet("background-color: #D2DCC4; border-radius: 20px;") + scrollWidget.setLayout(scrollLayout) + + scroll.verticalScrollBar().setStyleSheet(scroll_bar_style) + addButtonList = [] + exLabelList = [] + count = 0 + for i in range(16): + exLabel = QLabel(self) + exLabel.setFixedSize(367, 99) + exLabel.setStyleSheet("background-color: #5A8D6C; border-radius: 20px;") + exLabel1 = QLabel(exLabel) + exLabel1.move(10, 10) + exLabel1.setFixedSize(79, 79) + exLabel1.setStyleSheet(styleSheet5) + #add gif + + pic = QLabel(exLabel) + pic.setPixmap(QPixmap(self.listEx[i][6]).scaled(79, 79)) + pic.move(10, 10) + pic.setFixedSize(79, 79) + pic.setStyleSheet(styleSheet5) + + + addButton = QPushButton(exLabel) + addButton.setIcon(QIcon('img/add button.png')) + addButton.setIconSize(QPixmap('img/add button.png').size()) + addButton.setGeometry(320, 55, 36, 36) + addButton.move(320, 55) + addButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + # Tambahkan addButton ke dalam list + addButtonList.append(addButton) + exLabelList.append(exLabel) + # Hubungkan fungsi handleButtonClicked ke addButton + addButton.clicked.connect(lambda checked, index=i: handleButtonClicked(index, addButtonList)) + # addButton.clicked.connect(lambda checked, index=i: handleButtonClicked2(index, addButtonList)) + title = QLabel(exLabel) + # title.setText(f'<b><p><font style="font-size:24px;" color="#D2DCC4">{self.listEx[i][1]}</font><tab></p></b> <b><p><font color="#D2DCC4" style="font-size:14px;">{self.listEx[i][4]} Repetisi</font></p><b>') + title.setText(f'<font style="font-size:24px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[count][1]}<b>') + title.move(100, 15) + repDur = QLabel(exLabel) + if(count<8): + repDur.setText(f'<font style="font-size:14px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[count][4]} Seconds<b>') + repDur.move(100, 60) + else: + repDur.setText(f'<font style="font-size:14px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[count][5]} Repetition<b>') + repDur.move(100,60) + scrollLayout.addWidget(exLabel) + + addButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + count+=1 + scroll.setWidget(scrollWidget) + #greenCard2 + greenCard2 = QLabel(self) + greenCard2.move(577, 155) + greenCard2.setFixedSize(604, 534) + greenCard2.setStyleSheet(styleSheet) + scroll2 = QScrollArea(self) + scroll2.setWidgetResizable(True) + scroll2.setGeometry(620, 250, 410, 429) # mengatur posisi dan ukuran QScrollArea + scroll2.setStyleSheet("background-color: #D2DCC4;border-radius: none;") + scrollWidget2 = QWidget(scroll2) + scrollLayout2 = QVBoxLayout(scrollWidget2) + scrollWidget2.setStyleSheet("background-color: #D2DCC4; border-radius: 20px;") + scrollWidget2.setLayout(scrollLayout2) + scroll2.verticalScrollBar().setStyleSheet(scroll_bar_style) + scroll2.setWidget(scrollWidget2) + + area2 = [] + + if self.program_id != 0: + cur = self.con.cursor() + self.latihan = cur.execute(f"SELECT exercise_id FROM daftar_latihan NATURAL JOIN latihan_program WHERE program_id = {self.program_id}").fetchall() + for i in range(len(self.latihan)): + button = addButtonList[i] + button.setEnabled(False) + button.setIcon(QIcon('img/check button.png')) + button.setIconSize(QPixmap('img/check button.png').size()) + area2.append(self.latihan[i][0]) + exLabel = QLabel(self) + exLabel.setFixedSize(367, 99) + exLabel.setStyleSheet("background-color: #5A8D6C; border-radius: 20px;") + exLabel1 = QLabel(exLabel) + exLabel1.move(10, 10) + exLabel1.setFixedSize(79, 79) + exLabel1.setStyleSheet(styleSheet5) + + pic = QLabel(exLabel) + pic.setPixmap(QPixmap(self.listEx[i][6]).scaled(79, 79)) + pic.move(10, 10) + pic.setFixedSize(79, 79) + pic.setStyleSheet(styleSheet5) + # #add gif + # gif = QMovie('img/exe-pushup.gif') + # exLabel1.setMovie(gif) + # gif.start() + # gif.setScaledSize(QSize(79, 79)) + # gif.setSpeed(100) + title = QLabel(exLabel) + title.setText(f'<font style="font-size:24px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[i][1]}<b>') + title.move(100, 15) + repDur = QLabel(exLabel) + if(i<8): + repDur.setText(f'<font style="font-size:14px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[i][4]} Seconds<b>') + repDur.move(100, 60) + else: + repDur.setText(f'<font style="font-size:14px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[i][5]} Repetition<b>') + repDur.move(100,60) + deleteButton = QPushButton(exLabel) + deleteButton.setIcon(QIcon('img/delete button.png')) + deleteButton.setIconSize(QPixmap('img/delete button.png').size()) + deleteButton.setGeometry(320, 55, 36, 36) + deleteButton.move(320, 55) + deleteButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + deleteButton.clicked.connect(lambda checked, index=i: handleDeleteButtonClicked(index, exLabel, scrollLayout2)) + scrollLayout2.addWidget(exLabel) + + def handleButtonClicked(i, buttonList): + + area2.append(self.listEx[i][0]) + button = buttonList[i] + button.setEnabled(False) + button.setIcon(QIcon('img/check button.png')) + button.setIconSize(QPixmap('img/check button.png').size()) + exLabel = QLabel(self ) + exLabel.setFixedSize(367, 99) + exLabel.setStyleSheet("background-color: #5A8D6C; border-radius: 20px;") + exLabel1 = QLabel(exLabel) + exLabel1.move(10, 10) + exLabel1.setFixedSize(79, 79) + exLabel1.setStyleSheet(styleSheet5) + + pic = QLabel(exLabel) + pic.setPixmap(QPixmap(self.listEx[i][6]).scaled(79, 79)) + pic.move(10, 10) + pic.setFixedSize(79, 79) + pic.setStyleSheet(styleSheet5) + # #add gif + # gif = QMovie('img/exe-pushup.gif') + # exLabel1.setMovie(gif) + # gif.start() + # gif.setScaledSize(QSize(79, 79)) + # gif.setSpeed(100) + title = QLabel(exLabel) + title.setText(f'<font style="font-size:24px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[i][1]}<b>') + title.move(100, 15) + repDur = QLabel(exLabel) + if(i<8): + repDur.setText(f'<font style="font-size:14px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[i][4]} Seconds<b>') + repDur.move(100, 60) + else: + repDur.setText(f'<font style="font-size:14px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{self.listEx[i][5]} Repetition<b>') + repDur.move(100,60) + deleteButton = QPushButton(exLabel) + deleteButton.setIcon(QIcon('img/delete button.png')) + deleteButton.setIconSize(QPixmap('img/delete button.png').size()) + deleteButton.setGeometry(320, 55, 36, 36) + deleteButton.move(320, 55) + deleteButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + deleteButton.clicked.connect(lambda checked, index=i: handleDeleteButtonClicked(index, exLabel, scrollLayout2)) + scrollLayout2.addWidget(exLabel) + + def handleDeleteButtonClicked(index, exLabel, layout): + exLabel.setParent(None) + layout.removeWidget(exLabel) + exLabel.deleteLater() + for i, button in enumerate(addButtonList): + if i == index: + button.setEnabled(True) + button.setIcon(QIcon('img/add button.png')) + button.setIconSize(QPixmap('img/add button.png').size()) + + def saveButtonClicked(): + if(progNameInput.text().isalpha() == False): + QMessageBox.about(self, "Error", "Please input program name") + # QMessageBox.close() + else: + if(area2 == []): + QMessageBox.about(self, "Error", "Please add exercise") + # QMessageBox.close() + else: + QMessageBox.about(self, "Success", "Program saved") + # self.close() + cur = self.con.cursor() + data = cur.execute("SELECT program_id FROM program") + lenProg = len(data.fetchall()) + cur.execute( + f"INSERT INTO program (program_id, title_program) VALUES ({lenProg+1} ,'{progNameInput.text()}')" + ) + for i in area2: + cur.execute( + f"INSERT INTO latihan_program (program_id, exercise_id) VALUES ({lenProg+1} ,{i})" + ) + self.con.commit() + + + + + + + + font = QFont() + font.setFamily("Segoe UI") + font.setPointSize(28) + font.setBold(True) + + #font save + font1 = QFont() + font1.setFamily("Segoe UI") + font1.setPointSize(23) + font1.setBold(True) + + exText = QLabel(self) + exText.setText("Exercise") + exText.setFont(font) + exText.setStyleSheet(styleSheet2) + exText.setFixedSize(165, 35) + exText.move(140,185) + + progText = QLabel(self) + progText.setText("Program Name:") + progText.setStyleSheet(styleSheet2) + progText.setFixedSize(361, 50) + progText.setFont(font1) + progText.move(599, 182) + + progNameInput = QLineEdit(self) + progNameInput.move(840, 184) + progNameInput.setFixedSize(320, 50) + progNameInput.setFont(QFont("Segoe UI", 14)) + progNameInput.setStyleSheet(''' + padding: 11px 30px 11px 30px; + border: 1px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + color: #D2DCC4; + background-color: {background}; + } + QLineEdit::focus { + color: white; + selection-color: black; + selection-background-color: white; + } + ''') + + saveButton = QPushButton(self) + saveButton.setText('Save') + saveButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {button_color}; + border: none; + border-radius: 20px; + }} + ''') + saveButton.setFont(buttonFont) + saveButton.setFixedSize(95, 42) + saveButton.move(1065, 635) + saveButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + saveButton.clicked.connect(saveButtonClicked) + + def planWindow(self): + self.switch.emit("plan", 0, {}) + + def listWindow(self): + self.switch.emit("listLatihan", 0, {}) + + def dashboardWindow(self): + self.switch.emit("dashboard", 0, {}) + +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = customizeWorkout() + ex.show() + app.exec() \ No newline at end of file diff --git a/src/dashboard.py b/src/dashboard.py new file mode 100644 index 0000000000000000000000000000000000000000..8255fe90052c11820ab7fd3eac9c32a0cf1be56e --- /dev/null +++ b/src/dashboard.py @@ -0,0 +1,630 @@ +import sys + +from PyQt6.QtCore import Qt, pyqtSignal, QSize +from PyQt6.QtGui import QCursor, QFont, QPixmap, QMovie, QIcon +from PyQt6.QtWidgets import QApplication, QLabel, QPushButton, QWidget, QScrollArea, QVBoxLayout, QHBoxLayout +import sqlite3 +import random + +# cur = sqlite3.connect("fitu.db").cursor() + +background = '#5A8D6C' +button_color = '#174728' +text_color = '#EEEEE2' +card_color = '#D2DCC4' + + +# kumpulan font +helloFont = QFont() +helloFont.setFamily('Segoe UI') +helloFont.setPointSize(47) +# helloFont.setBold(True) + +quoteFont = QFont() +quoteFont.setFamily('Segoe UI') +quoteFont.setPointSize(25) + +buttonFont = QFont() +buttonFont.setFamily('Segoe UI') +buttonFont.setPointSize(18) +buttonFont.setBold(True) + +dateFont = QFont() +dateFont.setFamily('Segoe UI') +dateFont.setPointSize(23) +dateFont.setBold(True) + +historyFont = QFont() +historyFont.setFamily('Segoe UI') +historyFont.setPointSize(16) + +rincianFont = QFont() +rincianFont.setFamily('Segoe UI') +rincianFont.setPointSize(13) + +repetisiFont = QFont() +repetisiFont.setFamily('Segoe UI') +repetisiFont.setPointSize(10) + +styleSheetCard = ( + "background-color: #5A8D6C;" + "border-radius: 20px;" + ) + + +class dashboard(QWidget): + switch = pyqtSignal(str, int,dict) + def __init__(self, user=None): + super().__init__() + self.con = sqlite3.connect("fitu.db") + self.cur = self.con.cursor() + self.biodata = self.cur.execute("SELECT * FROM user").fetchall() + + self.index_history = int(-1) + self.banyaknyaKartu = int(-1) + self.dashboardWindow() + + def dashboardWindow(self): + self.setWindowTitle('FitU - Dashboard') + self.setWindowIcon(QIcon("img/logo.png")) + self.setFixedSize(1280, 720) + self.setStyleSheet(f'background-color: {background};') + self.label = QLabel("") + self.label.setParent(self) + self.element() + + def historyElement(self, historyIdx, idx): + # self.cur = self.con.cursor() + self.index_history = idx + tanggal = self.cur.execute(f""" + SELECT strftime(date) FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchone()[0] + + # menyiapkan history card + self.card = QLabel(self) + self.card.setPixmap(QPixmap('img/card-dashboard.png')) + self.card.move(633, 172) + + daftar_latihan = self.cur.execute(f""" + SELECT name FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchall() + + jumlahCard = len(daftar_latihan) + + self.banyaknyaKartu = jumlahCard + + self.date = QLabel(self) + self.date.setText(f"{tanggal}") + self.date.setStyleSheet(f'color: {button_color}; background-color: {card_color};') + self.date.move(820, 195) + self.date.setFont(dateFont) + self.date.setAlignment(Qt.AlignmentFlag.AlignLeft) + + keterangan = self.cur.execute(f""" + SELECT tot_duration, title_program FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchone() + self.duration = QLabel(self) + self.duration.setText("Duration : " + str(keterangan[0]) + " minutes") + self.duration.setStyleSheet(f'color: {button_color}; background-color: {card_color};') + self.duration.move(667,282) + self.duration.setFixedWidth(300) + self.duration.setFont(historyFont) + self.duration.setAlignment(Qt.AlignmentFlag.AlignLeft) + + self.prog = QLabel(self) + self.prog.setText("Program Name: " + keterangan[1]) + self.prog.setStyleSheet(f'color: {button_color}; background-color: {card_color};') + self.prog.move(667, 317) + self.prog.setFixedWidth(497) + self.prog.setFont(historyFont) + self.prog.setAlignment(Qt.AlignmentFlag.AlignLeft) + + + self.scroll = QScrollArea(self) + self.scroll.setGeometry(654, 369, 486, 204) # mengatur posisi dan ukuran QScrollArea + self.scroll.setStyleSheet(f"background-color: {card_color}; border-radius: 0px;") + self.scrollWidget = QWidget(self.scroll) + self.scrollLayout = QHBoxLayout(self.scrollWidget) + self.scrollWidget.setStyleSheet(f"background-color: {card_color}; border-radius: 0px;") + self.scrollWidget.setLayout(self.scrollLayout) + horizontal_scrollbar = self.scroll.horizontalScrollBar() + # Mengatur bentuk scroll bar + scroll_bar_style = """ + QScrollBar:horizontal { + border : 0px; + background-color: #D2DCC4; + height: 10px; + margin: 0px 0px 0px 0px; + } + QScrollBar::handle:horizontal { + background-color: #174728; + border-radius: 3px; + border: 0px; + } + """ + self.scroll.horizontalScrollBar().setStyleSheet(scroll_bar_style) + self.hbox = QHBoxLayout() + for j in range(self.banyaknyaKartu): + self.label = QLabel() + self.label.setFixedSize(150, 175) + self.label.setStyleSheet(styleSheetCard) + self.hbox.addWidget(self.label) + nama_latihan = daftar_latihan[j][0] + repetisi_latihan = self.cur.execute(f""" + SELECT repetition FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + durasi_latihan = self.cur.execute(f""" + SELECT duration FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + gambar_latihan = self.cur.execute(f""" + SELECT gif FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + self.con.commit() + self.show_nama_latihan = QLabel(self.label) + self.show_nama_latihan.setText(nama_latihan) + self.show_nama_latihan.setStyleSheet(f'color: {card_color};') + self.show_nama_latihan.move(10, 120) + self.show_nama_latihan.setFont(rincianFont) + self.show_nama_latihan.setAlignment(Qt.AlignmentFlag.AlignLeft) + + self.show_repetisi_latihan = QLabel(self.label) + if (repetisi_latihan[0] == None): + self.show_repetisi_latihan.setText("Duration: " + str(durasi_latihan[0]) + " seconds") + else: + self.show_repetisi_latihan.setText("Repetition: " + str(repetisi_latihan[0])) + self.show_repetisi_latihan.setStyleSheet(f'color: {card_color};') + self.show_repetisi_latihan.move(10, 145) + self.show_repetisi_latihan.setFont(repetisiFont) + self.show_repetisi_latihan.setAlignment(Qt.AlignmentFlag.AlignLeft) + + self.gif = self.cur.execute(f""" + SELECT gif FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone()[0] + self.gif2 = QMovie(self.gif) + self.gif2.setScaledSize(QSize(90, 90)) + self.gif2.start() + self.show_gambar_latihan = QLabel(self.label) + self.show_gambar_latihan.setMovie(self.gif2) + self.show_gambar_latihan.move(25, 20) + self.scrollLayout.addLayout(self.hbox) + self.scroll.setWidget(self.scrollWidget) + + self.kiri = QPushButton(self) + self.kiri.setText('<') + self.kiri.setStyleSheet(f''' + QPushButton {{ + color: {button_color}; + background-color: {card_color}; + border: none; + border-radius: 20px; + }} + ''') + self.kiri.setFont(dateFont) + self.kiri.move(727, 195) + self.kiri.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.kiri.clicked.connect(lambda:self.prev(historyIdx)) + + + self.kanan = QPushButton(self) + self.kanan.setText('>') + self.kanan.setStyleSheet(f''' + QPushButton {{ + color: {button_color}; + background-color: {card_color}; + border: none; + border-radius: 20px; + }} + ''') + self.kanan.setFont(dateFont) + self.kanan.move(1047, 195) + self.kanan.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.kanan.clicked.connect(lambda:self.next(historyIdx)) + + if (len(historyIdx) == 1): + self.kiri.hide() + self.kanan.hide() + elif(self.index_history == len(historyIdx)-1): + self.kanan.hide() + self.kiri.show() + elif (self.index_history == 0): + self.kiri.hide() + self.kanan.show() + else: + self.kiri.show() + self.kanan.show() + + def historyKosong(self): + # menyiapkan history card + self.card = QLabel(self) + self.card.setPixmap(QPixmap('img/card-dashboard.png')) + self.card.move(633, 172) + + self.text1 = QLabel(self) + self.text1.setText("You Haven't Completed\nAny Training yet!") + self.text1.setStyleSheet(f'color: {button_color}; background-color: {card_color};') + self.text1.move(743, 286) + dateFont.setBold(False) + self.text1.setFont(dateFont) + self.text1.setAlignment(Qt.AlignmentFlag.AlignCenter) + + + self.text2 = QLabel(self) + self.text2.setText("Let's start training now!") + self.text2.setStyleSheet(f'color: {button_color}; background-color: {card_color};') + self.text2.move(780, 448) + dateFont.setPointSize(18) + self.text2.setFont(dateFont) + dateFont.setBold(True) + dateFont.setPointSize(23) + self.text2.setAlignment(Qt.AlignmentFlag.AlignLeft) + + + def element(self): + self.cur = self.con.cursor() + # masukkan logo + logo = QLabel(self) + logo.setPixmap(QPixmap('img/logo-dashboard.png')) + logo.move(60, 45) + + # tombol home + homeButton = QPushButton(self) + homeButton.setText('Home') + homeButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {button_color}; + border: none; + border-radius: 20px; + }} + ''') + homeButton.setFont(buttonFont) + homeButton.setFixedSize(96, 42) #pake ini buat kalau dia buletan + homeButton.move(660, 53) + # homeButton.setCursor( + # QCursor(Qt.CursorShape.PointingHandCursor)) + + # tombol customize + customizeButton = QPushButton(self) + customizeButton.setText('Customize') + customizeButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: {button_color}; + }} + ''') + customizeButton.setFont(buttonFont) + customizeButton.move(798, 58) + customizeButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + customizeButton.clicked.connect(self.customWindow) + + # tombol plan + planButton = QPushButton(self) + planButton.setText('Plan') + planButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: {button_color}; + }} + ''') + planButton.setFont(buttonFont) + planButton.move(956, 58) + planButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + planButton.clicked.connect(self.planWindow) + + # tombol list + listButton = QPushButton(self) + listButton.setText('List') + listButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: {button_color}; + }} + ''') + listButton.setFont(buttonFont) + listButton.move(1047, 58) + listButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + listButton.clicked.connect(self.listWindow) + + # foto profil + profilePhoto = QLabel(self) + profilePhoto.setPixmap(QPixmap('img/profile-dashboard.png')) + profilePhoto.move(1133, 45) + + # say Hello + self.hello = QLabel(self) + # self.hello.setText(f"Hello, krisi!") + self.hello.move(101, 236) + self.hello.setFont(helloFont) + if(self.biodata == []): + self.hello.setText(f"Hello, dummy!") + else: + self.hello.setText(f"Hello, {self.biodata[0][0].split(' ')[0]}!") + self.hello.setStyleSheet(f'color: {text_color};') + self.hello.setAlignment(Qt.AlignmentFlag.AlignLeft) + + # quote + # quote + angka = random.randint(1, 7) + isi_quote = self.cur.execute(f"SELECT quote FROM quotes WHERE id = {angka}").fetchone() + quote = QLabel(self) + quote.setText(isi_quote[0]) + quote.setStyleSheet(f'color: {text_color};') + quote.move(101, 320) + quote.setFont(quoteFont) + quote.setAlignment(Qt.AlignmentFlag.AlignLeft) + + # tombol start + start = QPushButton(self) + start.setText("Let's Start!") + start.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {button_color}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: #5A8D6C; + background-color: #D2DCC4; + }} + ''') + start.setFont(buttonFont) + start.setFixedSize(233, 47) #pake ini buat kalau dia buletan + start.move(101, 511) + start.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + start.clicked.connect(self.planWindow) + + # membuat history card + historyIdx = self.cur.execute(""" + SELECT DISTINCT history_id FROM riwayat_latihan + """).fetchall() + + # menyiapkan history card + + if (len(historyIdx) <= 0): + self.historyKosong() + else: + tanggal = historyIdx[0][0] + idx = (len(historyIdx)-1) + self.historyElement(historyIdx, idx) + + def prev(self, historyIdx): + self.cur = self.con.cursor() + self.index_history -= 1 + if(self.index_history == len(historyIdx)-1): + self.kanan.hide() + self.kiri.show() + elif (self.index_history == 0): + self.kiri.hide() + self.kanan.show() + else: + self.kiri.show() + self.kanan.show() + self.scroll.setParent(None) + tanggal = self.cur.execute(f""" + SELECT strftime(date) FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchone()[0] + self.date.setText(f"{tanggal}") + daftar_latihan = self.cur.execute(f""" + SELECT name FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchall() + jumlahCard = len(daftar_latihan) + keterangan = self.cur.execute(f""" + SELECT tot_duration, title_program FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchone() + + self.duration.setText("Duration : " + str(keterangan[0]) + " minutes") + self.prog.setText("Program Name: " + keterangan[1]) + for i in reversed(range(self.banyaknyaKartu)): + self.hbox.itemAt(i).widget().setParent(None) + + self.scroll = QScrollArea(self) + self.scroll.setGeometry(654, 369, 486, 204) # mengatur posisi dan ukuran QScrollArea + self.scroll.setStyleSheet(f"background-color: {card_color}; border-radius: 0px;") + self.scrollWidget = QWidget(self.scroll) + self.scrollLayout = QVBoxLayout(self.scrollWidget) + self.scrollWidget.setStyleSheet(f"background-color: {card_color}; border-radius: 0px;") + self.scrollWidget.setLayout(self.scrollLayout) + horizontal_scrollbar = self.scroll.horizontalScrollBar() + # Mengatur bentuk scroll bar + scroll_bar_style = """ + QScrollBar:horizontal { + border : 0px; + background-color: #D2DCC4; + height: 10px; + margin: 0px 0px 0px 0px; + } + QScrollBar::handle:horizontal { + background-color: #174728; + border-radius: 3px; + border: 0px; + } + """ + self.scroll.horizontalScrollBar().setStyleSheet(scroll_bar_style) + self.hbox = QHBoxLayout() + + + self.banyaknyaKartu = jumlahCard + for j in range(self.banyaknyaKartu): + self.label = QLabel() + self.label.setFixedSize(150, 175) + self.label.setStyleSheet(styleSheetCard) + self.hbox.addWidget(self.label) + nama_latihan = daftar_latihan[j][0] + repetisi_latihan = self.cur.execute(f""" + SELECT repetition FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + durasi_latihan = self.cur.execute(f""" + SELECT duration FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + gambar_latihan = self.cur.execute(f""" + SELECT gif FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + self.con.commit() + self.show_nama_latihan = QLabel(self.label) + self.show_nama_latihan.setText(nama_latihan) + self.show_nama_latihan.setStyleSheet(f'color: {card_color};') + self.show_nama_latihan.move(10, 120) + self.show_nama_latihan.setFont(rincianFont) + self.show_nama_latihan.setAlignment(Qt.AlignmentFlag.AlignLeft) + + self.show_repetisi_latihan = QLabel(self.label) + if (repetisi_latihan[0] == None): + self.show_repetisi_latihan.setText("Duration: " + str(durasi_latihan[0]) + " seconds") + else: + self.show_repetisi_latihan.setText("Repetition: " + str(repetisi_latihan[0])) + self.show_repetisi_latihan.setStyleSheet(f'color: {card_color};') + self.show_repetisi_latihan.move(10, 145) + self.show_repetisi_latihan.setFont(repetisiFont) + self.show_repetisi_latihan.setAlignment(Qt.AlignmentFlag.AlignLeft) + + self.gif = self.cur.execute(f""" + SELECT gif FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone()[0] + self.gif2 = QMovie(self.gif) + self.gif2.setScaledSize(QSize(90, 90)) + self.gif2.start() + self.show_gambar_latihan = QLabel(self.label) + self.show_gambar_latihan.setMovie(self.gif2) + self.show_gambar_latihan.move(25, 20) + self.scrollLayout.addLayout(self.hbox) + self.scroll.setWidget(self.scrollWidget) + self.scroll.show() + + + + def next(self, historyIdx): + self.cur = self.con.cursor() + self.index_history += 1 + if(self.index_history == len(historyIdx)-1): + self.kanan.hide() + self.kiri.show() + elif (self.index_history == 0): + self.kiri.hide() + self.kanan.show() + else: + self.kiri.show() + self.kanan.show() + self.scroll.setParent(None) + tanggal = self.cur.execute(f""" + SELECT strftime(date) FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchone()[0] + self.date.setText(f"{tanggal}") + daftar_latihan = self.cur.execute(f""" + SELECT name FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchall() + jumlahCard = len(daftar_latihan) + keterangan = self.cur.execute(f""" + SELECT tot_duration, title_program FROM riwayat_latihan WHERE history_id = '{historyIdx[self.index_history][0]}' + """).fetchone() + + self.duration.setText("Duration : " + str(keterangan[0]) + " minutes") + self.prog.setText("Program Name: " + keterangan[1]) + + for i in reversed(range(self.banyaknyaKartu)): + self.hbox.itemAt(i).widget().setParent(None) + + self.scroll = QScrollArea(self) + self.scroll.setGeometry(654, 369, 486, 204) # mengatur posisi dan ukuran QScrollArea + self.scroll.setStyleSheet(f"background-color: {card_color}; border-radius: 0px;") + self.scrollWidget = QWidget(self.scroll) + self.scrollLayout = QVBoxLayout(self.scrollWidget) + self.scrollWidget.setStyleSheet(f"background-color: {card_color}; border-radius: 0px;") + self.scrollWidget.setLayout(self.scrollLayout) + horizontal_scrollbar = self.scroll.horizontalScrollBar() + # Mengatur bentuk scroll bar + scroll_bar_style = """ + QScrollBar:horizontal { + border : 0px; + background-color: #D2D2D2; + height: 10px; + margin: 0px 0px 0px 0px; + } + QScrollBar::handle:horizontal { + background-color: #174728; + border-radius: 3px; + border: 0px; + } + """ + self.scroll.horizontalScrollBar().setStyleSheet(scroll_bar_style) + self.hbox = QHBoxLayout() + + self.banyaknyaKartu = jumlahCard + for j in range(self.banyaknyaKartu): + self.label = QLabel() + self.label.setFixedSize(150, 175) + self.label.setStyleSheet(styleSheetCard) + self.hbox.addWidget(self.label) + nama_latihan = daftar_latihan[j][0] + repetisi_latihan = self.cur.execute(f""" + SELECT repetition FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + durasi_latihan = self.cur.execute(f""" + SELECT duration FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + gambar_latihan = self.cur.execute(f""" + SELECT gif FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone() + self.con.commit() + self.show_nama_latihan = QLabel(self.label) + self.show_nama_latihan.setText(nama_latihan) + self.show_nama_latihan.setStyleSheet(f'color: {card_color};') + self.show_nama_latihan.move(10, 120) + self.show_nama_latihan.setFont(rincianFont) + self.show_nama_latihan.setAlignment(Qt.AlignmentFlag.AlignLeft) + + self.show_repetisi_latihan = QLabel(self.label) + if (repetisi_latihan[0] == None): + self.show_repetisi_latihan.setText("Duration: " + str(durasi_latihan[0]) + " seconds") + else: + self.show_repetisi_latihan.setText("Repetition: " + str(repetisi_latihan[0])) + self.show_repetisi_latihan.setStyleSheet(f'color: {card_color};') + self.show_repetisi_latihan.move(10, 145) + self.show_repetisi_latihan.setFont(repetisiFont) + self.show_repetisi_latihan.setAlignment(Qt.AlignmentFlag.AlignLeft) + + self.gif = self.cur.execute(f""" + SELECT gif FROM daftar_latihan WHERE title = '{nama_latihan}' + """).fetchone()[0] + self.gif2 = QMovie(self.gif) + self.gif2.setScaledSize(QSize(90, 90)) + self.gif2.start() + self.show_gambar_latihan = QLabel(self.label) + self.show_gambar_latihan.setMovie(self.gif2) + self.show_gambar_latihan.move(25, 20) + self.scrollLayout.addLayout(self.hbox) + self.scroll.setWidget(self.scrollWidget) + self.scroll.show() + + def planWindow(self): + self.switch.emit("plan", 0, {}) + + def listWindow(self): + self.switch.emit("listLatihan",0, {}) + + def customWindow(self): + self.switch.emit("customize", 0, {}) + +if __name__ == '__main__': + app = QApplication(sys.argv) + window = dashboard() + window.show() + sys.exit(app.exec()) \ No newline at end of file diff --git a/src/endOfExercise.py b/src/endOfExercise.py new file mode 100644 index 0000000000000000000000000000000000000000..6b39d663555d5e6b494532b3d76e09586010fe48 --- /dev/null +++ b/src/endOfExercise.py @@ -0,0 +1,85 @@ +import sqlite3 +import sys +from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QLineEdit, QPushButton, QRadioButton, QCheckBox, QMessageBox +from PyQt6.QtGui import QFont, QPixmap, QCursor, QIcon +from PyQt6.QtCore import Qt, pyqtSignal + +class endOfExe(QWidget): + switch = pyqtSignal(str, dict) + def __init__(self): + super().__init__() + self.conn = sqlite3.connect('fitu.db') + self.setUpWindow() + + def setUpWindow(self): + self.setWindowTitle("FitU - End Of Exercise") + self.setFixedSize(1280, 720) + self.setWindowIcon(QIcon("img/logo.png")) + self.setUpEndOfExe() + + def setUpEndOfExe(self): + self.setStyleSheet('background-color: #5A8D6C') + + self.congratsSize = QFont() + self.congratsSize.setPointSize(40) + self.congratsSize.setFamily("Segoe UI") + self.congratsSize.setBold(True) + + self.stayHealSize = QFont() + self.stayHealSize.setPointSize(20) + self.stayHealSize.setFamily("Segoe UI") + self.stayHealSize.setBold(True) + + self.backSize = QFont() + self.backSize.setPointSize(15) + self.backSize.setFamily("Segoe UI") + # backSize.setBold(True) + + self.congrats = QLabel(self) + self.congrats.setText("Congratulations") + self.congrats.setFont(self.congratsSize) + self.congrats.setStyleSheet("color: #EEEEE2") + self.congrats.move(450, 170) + + self.done = QLabel(self) + self.done.setText("you've done the exercise!") + self.done.setFont(self.congratsSize) + self.done.setStyleSheet("color: #EEEEE2") + self.done.move(325, 250) + + self.stayHealthy = QLabel(self) + self.stayHealthy.setText("STAY HEALTHY AND POWERFUL!") + self.stayHealthy.setFont(self.stayHealSize) + self.stayHealthy.setStyleSheet("color: #EEEEE2") + self.stayHealthy.move(435, 375) + + self.backButtonon = QPushButton(self) + self.backButtonon.setText("Back To Dashboard") + self.backButtonon.setStyleSheet(''' + QPushButton { + color: rgba(255, 255, 255, 1); + background-color: #174728; + border-radius: 20; + } + QPushButton:hover { + background-color: #EEEEE2; + color: #174728; + } + ''') + self.backButtonon.resize(200, 50) + self.backButtonon.setFont(self.backSize) + self.backButtonon.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.backButtonon.move(560, 450) + self.backButtonon.clicked.connect(self.backToDash) + + + + def backToDash(self): + self.switch.emit("dashboard", {}) + +if __name__ == "__main__": + + app = QApplication(sys.argv) + window = endOfExe() + window.show() + app.exec() \ No newline at end of file diff --git a/src/listlatihan2.py b/src/listlatihan2.py new file mode 100644 index 0000000000000000000000000000000000000000..840cde59bcf8ce37799348aefd5edc968ab4d173 --- /dev/null +++ b/src/listlatihan2.py @@ -0,0 +1,339 @@ +import sqlite3 +import sys +from functools import partial + +from PyQt6.QtCore import Qt, QSize, pyqtSignal +from PyQt6.QtGui import QIcon, QPixmap, QCursor, QFont, QMovie +from PyQt6.QtWidgets import (QWidget, QApplication, QWidget, + QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QScrollArea, QDialog) + +background = '#5A8D6C' +button_color = '#174728' +text_color = '#EEEEE2' +card_color = '#D2DCC4' + +class listLatihan2(QWidget): + + switch = pyqtSignal(str, int, dict) + def __init__(self): + super().__init__() + self.con = sqlite3.connect('fitu.db') + self.listLat = self.fetchListLatihan() + self.count = 0 + self.setUpListLatihanWindow() + self.setupGUI() + + def fetchListLatihan(self): + cur = self.con.cursor() + rows = cur.execute("SELECT * FROM daftar_latihan") + rows = cur.fetchall() + cur.close() + return rows + + def setUpListLatihanWindow(self): + self.setFixedSize(1280,720) + self.setWindowIcon(QIcon("img/logo.png")) + self.setWindowTitle("FitU - Daftar Latihan") + self.setStyleSheet('background-color: #5A8D6C;') + + def openDetail(self, count, listLat): + popup = MyPopup(count, listLat) + popup.exec() + + def setupGUI(self): + + buttonFont = QFont() + buttonFont.setFamily('Segoe UI') + buttonFont.setPointSize(18) + + #STYLESHEET + styleSheetCard = ( + "background-color: #D2DCC4;" + "border-radius: 20px;" + ) + + + #NAVBAR + # masukkan logo + logo = QLabel(self) + logo.setPixmap(QPixmap('img/logo-dashboard.png')) + logo.move(60, 45) + + # tombol home + homeButton = QPushButton(self) + homeButton.setText('Home') + homeButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + font-weight: bold; + }} + QPushButton:hover {{ + color: {button_color}; + }} + ''') + homeButton.setFont(buttonFont) + homeButton.move(670, 58) + homeButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + homeButton.clicked.connect(self.dashboard) + + # tombol customize + customizeButton = QPushButton(self) + customizeButton.setText('Customize') + customizeButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + font-weight: bold; + }} + QPushButton:hover {{ + color: {button_color}; + }} + ''') + customizeButton.setFont(buttonFont) + customizeButton.move(798, 58) + customizeButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + customizeButton.clicked.connect(self.customWindow) + + # tombol plan + planButton = QPushButton(self) + planButton.setText('Plan') + planButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {background}; + border: none; + border-radius: 20px; + font-weight: bold; + }} + QPushButton:hover {{ + color: {button_color}; + }} + + ''') + planButton.setFont(buttonFont) + planButton.move(956, 58) + planButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + planButton.clicked.connect(self.planWindow) + + # tombol list + listButton = QPushButton(self) + listButton.setText('List') + listButton.setStyleSheet(f''' + QPushButton {{ + color: {text_color}; + background-color: {button_color}; + border: none; + border-radius: 20px; + font-weight: bold; + }} + ''') + listButton.setFont(buttonFont) + listButton.setFixedSize(96, 42) + listButton.move(1020, 53) + listButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + + # foto profil + profilePhoto = QLabel(self) + profilePhoto.setPixmap(QPixmap('img/profile-dashboard.png')) + profilePhoto.move(1133, 45) + + #Membuat scroll area + + + # scroll.setWidget(greenCard) + scroll = QScrollArea(self) + scroll.setGeometry(0, 150, 1265,570) # mengatur posisi dan ukuran QScrollArea + scroll.setStyleSheet("background-color: #5A8D6C;border-radius: none;") + scrollWidget = QWidget(scroll) + scrollLayout = QVBoxLayout(scrollWidget) + scrollWidget.setStyleSheet("background-color: #5A8D6C; border-radius: 20px;") + scrollWidget.setLayout(scrollLayout) + vertical_scrollbar = scroll.verticalScrollBar() + # Mengatur bentuk scroll bar + scroll_bar_style = """ + QScrollBar:vertical { + background-color: #D2DCC4; + width: 15px; + } + QScrollBar::handle:vertical { + background-color: #174728; + border-radius: 6px; + } + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 20px; + background-color: #D2DCC4; + subcontrol-origin: margin; + subcontrol-position: top; + } + QScrollBar::add-line:vertical { + top: 0; + } + QScrollBar::sub-line:vertical { + bottom: 0; + } + """ + scroll.verticalScrollBar().setStyleSheet(scroll_bar_style) + count = 0 + for j in range(5): + hbox = QHBoxLayout() + hbox.setContentsMargins(10, 0, 0, 0) + if(j<4): + for i in range (4): + card = QPushButton(self) + card.setFixedSize(266, 266) + card.setStyleSheet(styleSheetCard) + + pathImg = QPixmap(self.listLat[count][6]) + image = QLabel(card) + image.setPixmap(pathImg.scaled(100,100)) + image.move(83, 10) + + title = QLabel(card) + title.setText(f'<font style="font-size:24px;font-family="Sogoe UI;" ><b>{self.listLat[count][1]}<b>') + title.setStyleSheet("color: #174728") + title.move(10, 120) + + repDur = QLabel(card) + if(count<8): + repDur.setText(f'<font style="font-size:14px;font-family="Sogoe UI;"><b>{self.listLat[count][4]} Seconds<b>') + repDur.setStyleSheet("color: #174728") + repDur.move(185, 130) + else: + repDur.setText(f'<font style="font-size:14px;font-family="Sogoe UI;"><b>{self.listLat[count][5]} Repetition<b>') + repDur.setStyleSheet("color: #174728") + repDur.move(170,130) + + desc = QLabel(card) + t = f'<font style="font-size:12px;font-family="Sogoe UI;">{self.listLat[count][2]}' + if(len(t)> 200): + t = t[0:200]+f" <font color='#174728';;><b>See More...<b>" + + desc.setText(t) + desc.move(10, 170) + desc.setWordWrap(True) + desc.setFixedWidth(245) + desc.setFixedHeight(70) + desc.setAlignment(Qt.AlignmentFlag.AlignJustify) + desc.setStyleSheet("color: #174728") + self.count = count + hbox.addWidget(card) + card.clicked.connect(partial(self.openDetail, self.count, self.listLat)) + card.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + count+=1 + else: + box = QLabel() + box.setFixedHeight(12) + scrollLayout.addWidget(box) + + scrollLayout.addLayout(hbox) + scrollLayout.setSpacing(50) + + + scroll.setWidget(scrollWidget) + def customWindow(self): + self.switch.emit("customize", 0, {}) + + def planWindow(self): + self.switch.emit("plan", 0, {}) + + def dashboard(self): + self.switch.emit("dashboard",0, {}) + +class MyPopup(QDialog): + def __init__(self, count, listLat): + super().__init__() + + self.setWindowFlags(Qt.WindowType.FramelessWindowHint) + self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) + + styleSheet = ( + "background-color: #5A8D6C;" + "border-radius: 20px;" + ) + + styleSheet2 = ( + "background-color: #D2DCC4;" + "border-radius: 20px;" + ) + + bg = QLabel(self) + bg.setFixedSize(942, 464) + bg.move(198, 164) + bg.setStyleSheet("background-color: black; border-radius: 20px; color: #174728;") + + label = QLabel(bg) + label.setFixedSize(938,460) + label.move(2,2) + label.setStyleSheet(styleSheet2) + + + okButton = QPushButton(label) + okButton.setText("OK") + okButton.setFixedSize(70, 40) + okButton.move(840, 395) + okButton.setStyleSheet("color: #D2DCC4; background-color: #174728;font-weight: bold; font-size: 15px;") + okButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + okButton.clicked.connect(self.close) + + + pathGif = QMovie(listLat[count][6]) + pathGif.setScaledSize(QSize(325,325)) + pathGif.setSpeed(100) + gif = QLabel(bg) + gif.setMovie(pathGif) + gif.move(40,60) + gif.setStyleSheet("background-color: #D2DCC4;") + pathGif.start() + + garis = QLabel(bg) + garis.setFixedSize(2,440) + garis.setStyleSheet("background-color: #174728;") + garis.move(400,10) + + title = QLabel(bg) + title.setText(f'<font style="font-size:60px;font-family="Sogoe UI; ><b>{listLat[count][1]}<b>') + title.setStyleSheet("color: #174728; background-color: #D2DCC4;") + title.move(420, 40) + + goal = QLabel(bg) + goal.setText(f'<font style="font-size:26px;font-family="Sogoe UI; ><b>{listLat[count][3]}<b>') + goal.setStyleSheet("color: #174728; background-color: #D2DCC4;") + goal.move(420, 130) + + repDur = QLabel(bg) + if(count<8): + repDur.setText(f'<font style="font-size:17px;font-family="Sogoe UI;"><b>{listLat[count][4]} Seconds<b>') + repDur.move(755, 140) + else: + repDur.setText(f'<font style="font-size:17px;font-family="Sogoe UI;"><b>{listLat[count][5]} Repetition<b>') + repDur.move(735, 140) + repDur.setStyleSheet("color: #174728; background-color: #D2DCC4;") + + + desc = QLabel(bg) + desc.setText(f'<font style="font-size:14px;font-family="Sogoe UI; ><b>{listLat[count][2]}<b>') + desc.setStyleSheet("color: #174728; background-color: #D2DCC4;") + desc.setAlignment(Qt.AlignmentFlag.AlignJustify) + desc.move(420, 180) + desc.setWordWrap(True) + desc.setFixedWidth(410) + + + + + + +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = listLatihan2() + ex.show() + app.exec() \ No newline at end of file diff --git a/src/plan.py b/src/plan.py new file mode 100644 index 0000000000000000000000000000000000000000..7e7b69d55b67689285cc73d45ed825200154964b --- /dev/null +++ b/src/plan.py @@ -0,0 +1,395 @@ +import sqlite3 +import sys + +from PyQt6.QtCore import Qt, pyqtSignal +from PyQt6.QtGui import QPixmap, QCursor, QFont, QIcon +from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QScrollArea + +BACKGROUNDCOLOR = '#5A8D6C' +BUTTONCOLOR = '#174728' +TEXTCOLOR = '#EEEEE2' +CARDCOLOR = '#D2DCC4' + +class plan(QWidget): + switch = pyqtSignal(str, int, dict ) + def __init__(self): + super().__init__() + self.clickedRowData = 0 + self.con = sqlite3.connect('fitu.db') + self.programExercises = self.fetchProgramExercises() + self.planWindow() + + def fetchProgramExercises(self): + c = self.con.cursor() + c.execute("SELECT * FROM program") + data = c.fetchall() + c.close() + return data + + def planWindow(self): + self.label = QLabel("") + self.label.setParent(self) + self.setWindowTitle('FitU - Plan') + self.setWindowIcon(QIcon("img/logo.png")) + self.setFixedSize(1280, 720) + self.setStyleSheet(f'background-color: {BACKGROUNDCOLOR};') + self.elements() + + def elements(self): + buttonFont = QFont() + buttonFont.setFamily('Segoe UI') + buttonFont.setPointSize(18) + buttonFont.setBold(True) + + # Style sheets + styleSheetNavbar0 = (f''' + QPushButton {{ + color: {TEXTCOLOR}; + background-color: {BACKGROUNDCOLOR}; + border: none; + border-radius: 20px; + }} + QPushButton:hover {{ + color: {BUTTONCOLOR}; + }} + ''') + + styleSheetNavbar1 = (f''' + QPushButton {{ + color: {TEXTCOLOR}; + background-color: {BUTTONCOLOR}; + border: none; + border-radius: 20px; + }} + ''') + + styleSheetSmallCard = ( + ''' + QPushButton { + background-color: #5A8D6C; + border: 1.2px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + } + QPushButton:hover { + background-color: #174728; + border: 1.2px solid rgba(255, 255, 255, 0.8); + } + ''' + ) + + styleSheetBigCard = ( + "background-color: #D2DCC4;" + "border-radius: 20px;" + ) + + styleSheet = ( + "color: #5A8D6C;" + "background-color: #D2DCC4;" + "border-radius: 20px;" + ) + styleSheetStart = ( + f''' + QPushButton {{ + color: {TEXTCOLOR}; + background-color: {BACKGROUNDCOLOR}; + border: 1.2px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + }} + QPushButton:hover {{ + background-color: {BUTTONCOLOR}; + }} + ''') + + styleSheetCutomize = (f''' + QPushButton {{ + background-color: {CARDCOLOR}; + color: {BUTTONCOLOR}; + border: none; + border-radius: 20px; + text-decoration: underline; + }} + QPushButton:hover {{ + background-color: {CARDCOLOR}; + color: {BACKGROUNDCOLOR}; + }} + ''') + + verticallScrollBarStyle = (""" + QScrollBar:vertical { + background-color: white; + width: 8px; + margin: 20px 0 20px 0; + } + QScrollBar::handle:vertical { + background-color: #174728; + border-radius: 3px; + + } + QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 20px; + background-color: #D2DCC4; + subcontrol-origin: margin; + subcontrol-position: top; + } + QScrollBar::add-line:vertical { + top: 0; + } + QScrollBar::sub-line:vertical { + bottom: 0; + } + """) + + horizontalScrollBarStyle = (""" + QScrollBar:horizontal { + background-color: white; + height: 8px; + margin: 0 20px 0 20px; + } + QScrollBar::handle:horizontal { + background-color: #174728; + border-radius: 3px; + } + QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { + width: 20px; + background-color: #D2DCC4; + subcontrol-origin: margin; + subcontrol-position: left; + } + QScrollBar::add-line:horizontal { + left: 0; + } + QScrollBar::sub-line:horizontal { + right: 0; + } + """) + + # Navbar + # Navbar FitU logo + logo = QLabel(self) + logo.setPixmap(QPixmap('img/logo-dashboard.png')) + logo.move(60, 45) + + # tombol home + homeButton = QPushButton(self) + homeButton.setText('Home') + homeButton.setStyleSheet(styleSheetNavbar0) + homeButton.setFont(buttonFont) + homeButton.setFixedSize(96, 42) #pake ini buat kalau dia buletan + homeButton.move(660, 53) + homeButton.clicked.connect(self.dashboardWindow) + homeButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + + # tombol customize + customizeButton = QPushButton(self) + customizeButton.setText('Customize') + customizeButton.setStyleSheet(styleSheetNavbar0) + customizeButton.setFont(buttonFont) + customizeButton.move(798, 58) + customizeButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + customizeButton.clicked.connect(self.customWindow) + + # Plan Button + planButton = QPushButton(self) + planButton.setText('Plan') + planButton.setStyleSheet(styleSheetNavbar1) + planButton.setFont(buttonFont) + planButton.setFixedSize(80, 42) + planButton.move(942, 53) + + listButton = QPushButton(self) + listButton.setText('List') + listButton.setStyleSheet(styleSheetNavbar0) + listButton.setFont(buttonFont) + listButton.move(1047, 58) + listButton.setCursor( + QCursor(Qt.CursorShape.PointingHandCursor)) + listButton.clicked.connect(self.listWindow) + + # foto profil + profilePhoto = QLabel(self) + profilePhoto.setPixmap(QPixmap('img/profile-dashboard.png')) + profilePhoto.move(1133, 45) + + # Create Card + # Right Side + rightCard = QLabel(self) + rightCard.move(116, 155) + rightCard.setFixedSize(430, 534) + rightCard.setStyleSheet(styleSheetBigCard) + + # Right Scroll Area (Vertical) + scroll = QScrollArea(self) + scroll.setWidgetResizable(True) + scroll.setGeometry(130, 250, 410, 429) + scroll.setStyleSheet("background-color: #D2DCC4;border-radius: none;") + scrollWidget = QWidget(scroll) + scrollLayout = QVBoxLayout(scrollWidget) + scrollWidget.setStyleSheet("background-color: #D2DCC4; border-radius: 20px;") + scrollWidget.setLayout(scrollLayout) + + scroll.verticalScrollBar().setStyleSheet(verticallScrollBarStyle) + + # Fetch data from database + data = self.programExercises + row = len(data) + + + for i in range(row): + exButton = QPushButton(self) + exButton.setStyleSheet(styleSheetSmallCard) + exButton.setFixedSize(366, 99) + exButton.setFont(buttonFont) + exButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + exButton.clicked.connect(lambda state, index=i: showExercise(index)) + exButton.clicked.connect(self.enableStartButton) + title = QLabel(exButton) + title.setText(f'<font style="font-size:24px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{data[i][1]}<b>') + title.move(20, 15) + title.setStyleSheet("background-color: transparent;") + + con = sqlite3.connect('fitu.db') + c = con.cursor() + c.execute("SELECT title FROM latihan_program, daftar_latihan WHERE latihan_program.exercise_id = daftar_latihan.exercise_id AND latihan_program.program_id = ?", (data[i][0],)) + self.data2 = c.fetchall() + # c.commit() + c.close() + + + # self.enableStartButton() + predict = len(self.data2) + dur = QLabel(exButton) + dur.setText(f'<font style="font-size:18px;" color="#D2DCC4"; font-family="Sogoe UI";>{predict} Minutes') + dur.move(20, 50) + dur.setStyleSheet("background-color: transparent;") + scrollLayout.addWidget(exButton) + scroll.setWidget(scrollWidget) + + # Left Side + leftCard = QLabel(self) + leftCard.move(577, 155) + leftCard.setFixedSize(604, 534) + leftCard.setStyleSheet(styleSheetBigCard) + + scroll2 = QScrollArea(self) + scroll2.setWidgetResizable(True) + scroll2.setGeometry(610, 230, 545, 350) # mengatur posisi dan ukuran QScrollArea + scroll2.setStyleSheet("background-color: #D2DCC4;border-radius: none;") + scrollWidget2 = QWidget(scroll2) + scrollLayout2 = QHBoxLayout(scrollWidget2) + scrollWidget2.setStyleSheet("background-color: #D2DCC4; border-radius: 20px;") + scrollWidget2.setLayout(scrollLayout2) + + scroll2.horizontalScrollBar().setStyleSheet(horizontalScrollBarStyle) + # create a list to store the exercise data + exercise_data = [] + + # create a function to show exercise data based on index + def showExercise(index): + self.clickedRowData = data[index][0] + con = sqlite3.connect('fitu.db') + c = con.cursor() + c.execute("SELECT title, repetition, duration, gif FROM latihan_program, daftar_latihan WHERE latihan_program.exercise_id = daftar_latihan.exercise_id AND latihan_program.program_id = ?", (self.clickedRowData,)) + self.data3 = c.fetchall() + c.close() + + # clear the exercise data list + exercise_data.clear() + + # append new exercise data to the list + for i in range(len(self.data3)): + exercise_data.append(self.data3[i]) + + # remove all widgets from scrollLayout2 + for i in reversed(range(scrollLayout2.count())): + scrollLayout2.itemAt(i).widget().setParent(None) + + # create QLabel widgets for each exercise and add them to scrollLayout2 + for i in range(len(exercise_data)): + exLabel = QLabel(self) + exLabel.setFixedSize(202, 270) + exLabel.setStyleSheet("background-color: #5A8D6C; border-radius: 20px;") + title = QLabel(exLabel) + title.setText(f'<font style="font-size:22px;" color="#D2DCC4"; font-family="Sogoe UI";><b>{exercise_data[i][0]}<b>') + title.move(20, 15) + repDur = QLabel(exLabel) + if exercise_data[i][1] == None: + repDur.setText(f'<font style="font-size:18px;" color="#D2DCC4"; font-family="Sogoe UI";>{exercise_data[i][2]} Seconds') + else: + repDur.setText(f'<font style="font-size:18px;" color="#D2DCC4"; font-family="Sogoe UI";>{exercise_data[i][1]} Repetitions') + repDur.move(20, 50) + exPix = QPixmap(exercise_data[i][3]) + image = QLabel(exLabel) + image.setPixmap(exPix) + image.setScaledContents(True) + image.move(20, 80) + image.setFixedSize(160, 160) + + scrollLayout2.addWidget(exLabel) + scroll2.setWidget(scrollWidget2) + + font = QFont() + font.setFamily("Segoe UI") + font.setPointSize(28) + font.setBold(True) + + #font save + font1 = QFont() + font1.setFamily("Segoe UI") + font1.setPointSize(23) + font1.setBold(True) + + exText = QLabel(self) + exText.setText("Workout Plan") + exText.setFont(font) + exText.setStyleSheet(styleSheet) + exText.setFixedSize(250, 50) + exText.move(140,185) + + progText = QLabel(self) + progText.setText("Exercise") + progText.setStyleSheet(styleSheet) + progText.setFixedSize(165, 50) + progText.setFont(font) + progText.move(599, 182) + + self.startButton = QPushButton(self) + self.startButton.setFont(font) + self.startButton.setText("START >") + self.startButton.move(1004, 620) + self.startButton.setFixedSize(144, 42) + self.startButton.setStyleSheet(styleSheetStart) + self.startButton.setFont(font1) + self.startButton.setEnabled(False) + self.startButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.startButton.clicked.connect(self.plan2Window) + + custButton = QPushButton(self) + custButton.setFont(font) + custButton.setText("Customize") + custButton.move(825, 620) + custButton.setStyleSheet(styleSheetCutomize) + custButton.setFont(font1) + custButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + custButton.clicked.connect(self.customWindow) + + def dashboardWindow(self): + self.switch.emit("dashboard",0, {}) + + def listWindow(self): + self.switch.emit("listLatihan", 0, {}) + + def customWindow(self): + self.switch.emit("customize", self.clickedRowData, {}) + + def plan2Window(self): + self.switch.emit("plan2", self.clickedRowData, {}) + + def enableStartButton(self): + self.startButton.setEnabled(True) + +if __name__ == '__main__': + app = QApplication(sys.argv) + ex = plan() + ex.show() + app.exec() diff --git a/src/plan2.py b/src/plan2.py new file mode 100644 index 0000000000000000000000000000000000000000..bc2ae0ab078ce0f1fc1a23a22802045e1cfca69a --- /dev/null +++ b/src/plan2.py @@ -0,0 +1,220 @@ +import sqlite3 +from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QPushButton, QMessageBox +from PyQt6.QtGui import QFont, QPixmap, QCursor, QMovie, QIcon +from PyQt6.QtCore import Qt, QSize, QUrl, QTimer, pyqtSignal +from PyQt6.QtMultimedia import QMediaPlayer +from plan import plan +import time +# from PyQt6.QtMultimedia import QSoundEffect +import time +import sys +class plan2(QWidget): + switch = pyqtSignal(str, int, dict) + def __init__(self, program_id): + super().__init__() + self.index = 0 + self.conn = sqlite3.connect("fitu.db") + self.c = self.conn.cursor() + self.program_id = program_id + self.latihan = self.c.execute(f"SELECT gif FROM daftar_latihan NATURAL JOIN latihan_program WHERE program_id = {self.program_id}").fetchall() + self.timer = QTimer(self) + self.timer.timeout.connect(self.updateTimer) + self.remaining_time = 0 # initial value in seconds + self.timer.start(1000) # set timer to update every second + self.setUpWindowPlan() + + # self.setUpRegisterWindow() + def setUpWindowPlan(self): + self.setWindowTitle("FitU - Exercise") + self.setFixedSize(1280, 720) + self.setWindowIcon(QIcon("img/logo.png")) + self.setUpPlan() + + def updateTimer(self): + if int(self.remaining_time) > 0: + self.remaining_time = int(self.remaining_time) - 1 + minutes = int(self.remaining_time) // 60 + seconds = int(self.remaining_time) % 60 + self.timer_label.setText(f"{minutes:02d}:{seconds:02d}") + else: + self.timer.stop() + QMessageBox.information(self, "Time's up!", "Let's go to next exercise!") + + def resetTimer(self): + self.remaining_time = self.duration[self.index][0] + self.timer.start(1000) + if(int(self.duration[self.index][0])<59): + self.timer_label.setText("00:"+str(self.remaining_time)) + else: + self.timer_label.setText("00:"+str(self.remaining_time)) + def repetitionLabel(self): + self.timer.stop() + self.timer_label.setText(str(self.repCount[self.index][0])+ " Rep") + + def setUpPlan(self): + self.setStyleSheet('background-color: #5A8D6C') + + backButton = QPushButton(self) + backButton.setGeometry(200, 150, 100, 100) + backButton.resize(60, 60) + backButton.setIcon(QIcon("img/arrow-left.png")) + backButton.setIconSize(QPixmap("img/arrow-left.png").size()) + backButton.setStyleSheet("background-color: #174728; color: #EEEEE2; border-radius: 30px; border: 2px;") + backButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + backButton.move(50, 64) + backButton.clicked.connect(lambda: self.switch.emit("plan", 0, {})) + + self.currEx = QLabel(self) + self.currEx.setFixedSize(360, 335) + self.currEx.move(460, 105) + self.currEx.setStyleSheet("background-color: #EEEEE2; border-radius: 25px; border: 2px") + self.movie = QMovie(self.latihan[0][0]) + self.currEx.setMovie(self.movie) + self.movie.start() + self.currEx.setScaledContents(True) + self.movie.setSpeed(60) + + self.nextButton = QPushButton(self) + self.nextButton.setGeometry(200, 150, 100, 100) + self.nextButton.setIcon(QIcon("img/arrow-right.png")) + self.nextButton.setIconSize(QPixmap("img/arrow-right.png").size()) + self.nextButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.nextButton.setStyleSheet(''' + QPushButton{ + border: 5px #5A8D6C; + } + QPushButton:hover { + background-color: #174728; + }''') + self.nextButton.move(700, 581) + self.nextButton.clicked.connect(self.nextEx) + + self.prevButton = QPushButton(self) + self.prevButton.setGeometry(200, 150, 100, 100) + self.prevButton.setIcon(QIcon("img/arrow-left.png")) + self.prevButton.setIconSize(QPixmap("img/arrow-left.png").size()) + self.prevButton.setStyleSheet(''' + QPushButton{ + border: 5px #5A8D6C; + } + QPushButton:hover { + background-color: #174728; + }''') + self.prevButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.prevButton.move(513, 581) + self.prevButton.clicked.connect(self.prevEx) + + + self.name = self.c.execute(f"SELECT title FROM daftar_latihan NATURAL JOIN latihan_program WHERE program_id = {self.program_id}").fetchall() + self.nameLabel = QLabel(self) + self.nameLabel.setText(self.name[self.index][0]) + self.nameLabel.setFont(QFont("Segoe UI", 20, QFont.Weight.Bold)) + self.nameLabel.setWordWrap(True) + self.nameLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.nameLabel.setStyleSheet("color: #EEEEE2") + self.nameLabel.move(0, 461) + self.nameLabel.setFixedWidth(1280) + + # duration = QLabel(self) + self.repLabel = QLabel(self) + self.repLabel.setFont(QFont("Segoe UI", 20, QFont.Weight.Bold)) + self.repLabel.setStyleSheet("color: #EEEEE2") + self.repLabel.move(547, 510) + + self.timer_label = QLabel(self) + self.timer_label.setGeometry(0, 0, 200, 50) + self.timer_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.timer_label.move(547, 510) + self.timer_label.setFont(QFont("Segoe UI", 20, QFont.Weight.Bold)) + self.timer_label.setStyleSheet("background-color: #EEEEE2; border-radius: 10px; border: 2px") + self.start = time.time() + # durationCount = c.execute(f"SELECT duration FROM daftar_self.latihan WHERE exercise_id in (SELECT exercise_id FROM self.latihan_program WHERE program_id = 1)").fetchall() + self.repCount = self.c.execute(f"SELECT repetition FROM daftar_latihan NATURAL JOIN latihan_program WHERE program_id = {self.program_id}").fetchall() + self.duration = self.c.execute(f"SELECT duration FROM daftar_latihan NATURAL JOIN latihan_program WHERE program_id = {self.program_id}").fetchall() + + if self.duration[self.index][0] != None: + self.remaining_time = self.duration[self.index][0] + self.resetTimer() + else: + self.repetitionLabel() + + self.historyButton = QPushButton(self) + self.historyButton.setFixedSize(80, 80) + self.historyButton.setEnabled(False) + self.historyButton.setText("end") + self.historyButton.setFont(QFont("Segoe UI", 20, QFont.Weight.Bold, )) + + self.historyButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.historyButton.setStyleSheet(''' + QPushButton{ + border: 5px #5A8D6C; + color: #EEEEE2; + border-radius: 30px; + } + QPushButton:hover { + background-color: #174728; + }''') + self.historyButton.move(615, 585) + self.historyButton.clicked.connect(self.addHistory) + + def prevEx(self): + if self.index > 0: + self.index -= 1 + self.movie = QMovie(self.latihan[self.index][0]) + self.currEx.setMovie(self.movie) + self.movie.start() + self.movie.setScaledSize(QSize(330, 305)) + self.movie.setSpeed(60) + + if self.duration[self.index][0] != None: + self.remaining_time = self.duration[self.index][0] + self.resetTimer() + else: + self.repetitionLabel() + self.nameLabel.setText(self.name[self.index][0]) + + + + + def nextEx(self): + if self.index < (len(self.latihan)) - 1: + self.index += 1 + self.movie = QMovie(self.latihan[self.index][0]) + self.currEx.setMovie(self.movie) + self.movie.start() + self.movie.setScaledSize(QSize(330, 305)) + self.movie.setSpeed(100) + + if self.duration[self.index][0] != None: + self.remaining_time = self.duration[self.index][0] + self.resetTimer() + else: + self.repetitionLabel() + self.nameLabel.setText(self.name[self.index][0]) + if self.index == (len(self.latihan)) - 1: + self.historyButton.setEnabled(True) + + + def addHistory(self): + # if self.index +1 >= len(self.latihan): + self.timer.stop() + self.nextButton.setEnabled(False) + titleProgram = self.c.execute(f"SELECT title_program FROM program WHERE program_id = {self.program_id}").fetchone() + nameExe = self.c.execute(f"SELECT title FROM daftar_latihan WHERE exercise_id in (SELECT exercise_id FROM latihan_program WHERE program_id = {self.program_id})").fetchall() + date = time.strftime("%Y-%m-%d", time.localtime()) + histId = self.c.execute("SELECT DISTINCT history_id FROM riwayat_latihan").fetchall() + totDuration = (time.time() - self.start) // 60 + for i in range (len(self.latihan)): + self.c.execute(f"""INSERT INTO riwayat_latihan (history_id, program_id, name, title_program, date, calories, tot_duration) + VALUES + ({len(histId)+401}, {self.program_id}, '{nameExe[i][0]}', '{(titleProgram[0])}', '{date}', NULL, {int(totDuration)})""") + self.conn.commit() + self.switch.emit("endOfExe",0, {}) + + +if __name__ == "__main__": + + app = QApplication(sys.argv) + window = plan2() + window.show() + app.exec() diff --git a/src/register.py b/src/register.py new file mode 100644 index 0000000000000000000000000000000000000000..0d5d8c690550fda30f22adc9ed74ae4474a32662 --- /dev/null +++ b/src/register.py @@ -0,0 +1,223 @@ +import sqlite3 +from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QLineEdit, QPushButton, QRadioButton, QCheckBox, QMessageBox +from PyQt6.QtGui import QFont, QPixmap, QCursor, QIcon +from PyQt6.QtCore import Qt, pyqtSignal +import sys +class register(QWidget): + switch = pyqtSignal() + def __init__(self): + super().__init__() + self.conn = sqlite3.connect('fitu.db') + self.setUpWindow() + + def setUpWindow(self): + self.setWindowTitle("FitU - Register") + self.setWindowIcon(QIcon("img/logo.png")) + self.setFixedSize(1280, 720) + self.setUp() + + def setUp(self): + #Background + background = QLabel(self) + bacgroundImage = QPixmap("img/register-page.png") + background.setPixmap(bacgroundImage) + background.move(0, 0) + + inputSize = QFont() + inputSize.setFamily("Segoe UI") + inputSize.setPointSize(10) + + genderSize = QFont() + genderSize.setFamily("Segoe UI") + genderSize.setPointSize(14) + + registerText = QFont() + registerText.setFamily("Segoe UI") + registerText.setPointSize(16) + + self.nameInput = QLineEdit(self) + self.nameInput.setPlaceholderText("Input Your Name") + self.nameInput.setFixedSize(379, 44) + self.nameInput.setFont(inputSize) + self.nameInput.setStyleSheet(''' + padding: 11px 30px 11px 30px; + border: 1px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + color: rgba(23, 71, 40, 1); + background-color: #D2DCC4 + ''') + self.nameInput.move(773, 196) + + self.age = QLineEdit(self) + self.age.setPlaceholderText("Input Your Age") + self.age.setFixedSize(172, 44) + self.age.setFont(inputSize) + self.age.setStyleSheet(''' + padding: 11px 30px 11px 30px; + border: 1px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + color: rgba(23, 71, 40, 1); + background-color: #D2DCC4 + ''') + self.age.move(976, 285) + + self.height = QLineEdit(self) + self.height.setPlaceholderText("Input Your Height") + self.height.setFixedSize(172, 44) + self.height.setFont(inputSize) + self.height.setStyleSheet(''' + padding: 11px 30px 11px 30px; + border: 1px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + color: rgba(23, 71, 40, 1); + background-color: #D2DCC4 + ''') + self.height.move(769, 392) + + self.weight = QLineEdit(self) + self.weight.setPlaceholderText("Input Your Weight") + self.weight.setFixedSize(172, 44) + self.weight.setFont(inputSize) + self.weight.setStyleSheet(''' + padding: 11px 30px 11px 30px; + border: 1px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + color: rgba(23, 71, 40, 1); + background-color: #D2DCC4 + ''') + self.weight.move(976, 392) + + self.male = QRadioButton(self) + self.male.move(780, 285) + self.male.setStyleSheet(f'background-color: #174728 ; color: #D2DCC4 ') + self.male.setText("Male") + self.male.setFont(genderSize) + self.male.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + + self.female = QRadioButton(self) + self.female.move(780, 315) + self.female.setStyleSheet('background-color: #174728 ; color: #D2DCC4 ') + self.female.setText("Female") + self.female.setFont(genderSize) + self.female.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + + self.registerButton = QPushButton(self) + self.registerButton.setText("Register") + self.registerButton.setFixedSize(172, 44) + self.registerButton.setStyleSheet(''' + QPushButton { + color: rgba(23, 71, 40, 1); + background-color: #D2DCC4; + border: 1px solid rgba(255, 255, 255, 0.8); + border-radius: 20px; + } + QPushButton:hover { + background-color: #5A8D6C; + color: #D2DCC4; + } + ''') + self.registerButton.move(873, 545) + self.registerButton.setFont(registerText) + self.registerButton.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.registerButton.clicked.connect(self.register) + + + self.fit = QCheckBox(self) + self.fit.move(781, 486) + self.fit.setText("Fit our body") + self.fit.setFont(genderSize) + self.fit.setStyleSheet('background-color: #174728 ; color: #D2DCC4 ') + self.fit.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + + self.thin = QCheckBox(self) + self.thin.move(781, 516) + self.thin.setText("Thin") + self.thin.setFont(genderSize) + self.thin.setStyleSheet('background-color: #174728 ; color: #D2DCC4 ') + self.thin.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + + def register(self): + if (self.nameInput.text() == '' or self.age.text() == '' or self.height.text() == '' or self.weight.text() == '' + or (not self.male.isChecked() and not self.female.isChecked()) + or (not self.fit.isChecked() and not self.thin.isChecked())): + msgBox = QMessageBox() + msgBox.setText("<p>Please fill out the form properly!</p>") + msgBox.setWindowTitle("Registration Failed") + msgBox.setIcon(QMessageBox.Icon.Warning) + msgBox.setStyleSheet("background-color: white") + msgBox.setStandardButtons(QMessageBox.StandardButton.Ok) + msgBox.exec() + return + # elif (not self.nameInput.text().isalpha() and self.nameInput.text().isspace()): + # msgBox = QMessageBox() + # msgBox.setText("<p>Name must be in alphabet</p>") + # msgBox.setWindowTitle("Registration Failed") + # msgBox.setIcon(QMessageBox.Icon.Warning) + # msgBox.setStyleSheet("background-color: white") + # msgBox.setStandardButtons(QMessageBox.StandardButton.Ok) + # msgBox.exec() + # return + + elif not self.age.text().isdigit() or not self.height.text().isdigit() or not self.weight.text().isdigit(): + msgBox = QMessageBox() + msgBox.setText("<p>Age, Height, and Weight must be in number</p>") + msgBox.setWindowTitle("Registration Failed") + msgBox.setIcon(QMessageBox.Icon.Warning) + msgBox.setStyleSheet("background-color: white") + msgBox.setStandardButtons(QMessageBox.StandardButton.Ok) + msgBox.exec() + + else: + c = self.conn.cursor() + if (self.female.isChecked()): + if (self.fit.isChecked() == self.thin.isChecked()): + c.execute( + f"INSERT INTO user (name, height, weight, goal, gender, age) VALUES ('{self.nameInput.text()}', '{self.height.text()}', '{self.weight.text()}', 'fit, thin', 'female', '{self.age.text()}')" + ) + self.conn.commit() + elif (self.thin.isChecked()): + c.execute( + f"INSERT INTO user (name, height, weight, goal, gender, age) VALUES ('{self.nameInput.text()}', '{self.height.text()}', '{self.weight.text()}', 'thin', 'female', '{self.age.text()}')" + ) + self.conn.commit() + elif (self.fit.isChecked()): + c.execute( + f"INSERT INTO user (name, height, weight, goal, gender, age) VALUES ('{self.nameInput.text()}', '{self.height.text()}', '{self.weight.text()}', 'fit', 'female', '{self.age.text()}')" + ) + self.conn.commit() + # if (self.fit and self.thin): + + + + elif(self.male.isChecked()): + if(self.fit.isChecked() and self.thin.isChecked()): + c.execute( + f"INSERT INTO user (name, height, weight, goal, gender, age) VALUES ('{self.nameInput.text()}', '{self.height.text()}', '{self.weight.text()}', 'fit, thin', 'male', '{self.age.text()}')" + ) + self.conn.commit() + elif (self.thin.isChecked()): + c.execute( + f"INSERT INTO user (name, height, weight, goal, gender, age) VALUES ('{self.nameInput.text()}', '{self.height.text()}', '{self.weight.text()}', 'thin', 'male', '{self.age.text()}')" + ) + self.conn.commit() + + elif (self.fit.isChecked()): + c.execute( + f"INSERT INTO user (name, height, weight, goal, gender, age) VALUES ('{self.nameInput.text()}', '{self.height.text()}', '{self.weight.text()}', 'fit', 'male', '{self.age.text()}')" + ) + self.conn.commit() + # if (self.fit and self.thin): + + + self.nameInput.clear() + self.age.clear() + self.height.clear() + self.weight.clear() + self.switch.emit() + +if __name__ == "__main__": + + app = QApplication(sys.argv) + window = register() + window.show() + app.exec() \ No newline at end of file diff --git a/test/test_dashboard.py b/test/test_dashboard.py new file mode 100644 index 0000000000000000000000000000000000000000..19e42a4c23e4dc471d2fea0aead65615fc26df14 --- /dev/null +++ b/test/test_dashboard.py @@ -0,0 +1,47 @@ +import pytest +import sys +import os + +path = os.getcwd() +sys.path.insert(0,f"{path}/src") + +from PyQt6.QtCore import Qt, pyqtSignal, QSize +from PyQt6.QtGui import QCursor, QFont, QPixmap, QMovie, QIcon +from PyQt6.QtWidgets import QApplication, QLabel, QPushButton, QWidget, QScrollArea, QVBoxLayout, QHBoxLayout +import sqlite3 +import random + +from dashboard import dashboard + +cur = sqlite3.connect('fitu.db') +con = cur.cursor() + +@pytest.fixture +def app(): + app = dashboard() + yield app + +def test_dashboard(app, qtbot): + assert app.windowTitle() == 'FitU - Dashboard' + assert app.height() == 720 + assert app.width() == 1280 + +def test_element(app, qtbot): + latihan = cur.execute(""" + SELECT * FROM riwayat_latihan """).fetchall() + + if (len(latihan)<=0): + assert len(app.findChildren(QPushButton)) == 5 + assert len(app.findChildren(QLabel)) == 8 + else: + assert len(app.findChildren(QPushButton)) == 7 + assert len(app.findChildren(QLabel)) == 21 + assert app.findChildren(QPushButton)[0].text() == 'Home' + assert app.findChildren(QPushButton)[1].text() == 'Customize' + assert app.findChildren(QPushButton)[2].text() == 'Plan' + assert app.findChildren(QPushButton)[3].text() == 'List' + assert app.findChildren(QPushButton)[4].text() == "Let's Start!" + + + + diff --git a/test/test_endOfExe.py b/test/test_endOfExe.py new file mode 100644 index 0000000000000000000000000000000000000000..a81a111a05cc6e34e49c6e5f36b43f7f3883437d --- /dev/null +++ b/test/test_endOfExe.py @@ -0,0 +1,41 @@ +import sqlite3 +import sys +from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QLineEdit, QPushButton, QRadioButton, QCheckBox, QMessageBox +from PyQt6.QtGui import QFont, QPixmap, QCursor +from PyQt6.QtCore import Qt, pyqtSignal +import sys +import os +import pytest + +path = os.getcwd() +sys.path.insert(0,f"{path}/src") +from endOfExercise import endOfExe + +def test_endOfExe(qtbot): + window = endOfExe() + qtbot.addWidget(window) + + + # Check window title and size + assert window.windowTitle() == "FitU - End Of Exercise" + assert window.size() == window.minimumSize() + + # Check presence and properties of all widgets + assert isinstance(window.findChildren(QLabel)[0], QLabel) + assert window.findChildren(QLabel)[0].text() == "Congratulations" + assert isinstance(window.findChildren(QLabel)[1], QLabel) + assert window.findChildren(QLabel)[1].text() == "you've done the exercise!" + assert isinstance(window.findChildren(QLabel)[2], QLabel) + assert window.findChildren(QLabel)[2].text() == "STAY HEALTHY AND POWERFUL!" + assert isinstance(window.findChildren(QPushButton)[0], QPushButton) + assert window.findChildren(QPushButton)[0].text() == "Back To Dashboard" + + # Assume we have a parent widget called 'parentWidget' +# and we want to find a child QLabel with object name 'myLabel' + + + + # Test clicking on the back button emits the signal + # with qtbot.waitSignal(window.switch, raising=True) as blocker: + # qtbot.mouseClick(window.findChild(QPushButton, "backButton"), Qt.MouseButton.LeftButton) + # assert blocker.args == ("dashboard", {}) diff --git a/test/test_listlatihan2.py b/test/test_listlatihan2.py new file mode 100644 index 0000000000000000000000000000000000000000..8eb8a444a5048befd82c427aa8a2061fcafa289a --- /dev/null +++ b/test/test_listlatihan2.py @@ -0,0 +1,30 @@ +from PyQt6.QtWidgets import QApplication +import sys +import os + +path = os.getcwd() +sys.path.insert(0,f"{path}/src") +from listlatihan2 import listLatihan2 +from PyQt6.QtCore import Qt, QSize, pyqtSignal +from PyQt6.QtGui import QIcon, QPixmap, QCursor, QFont, QMovie +from PyQt6.QtWidgets import (QWidget, QApplication, QWidget, + QLabel, QVBoxLayout, QHBoxLayout, QPushButton, QScrollArea, QDialog) +import pytest + +@pytest.fixture +def app(): + app = listLatihan2() + yield app + +def test_window(app,qtbot): + # cek window title + assert app.windowTitle() == "FitU - Daftar Latihan" + assert app.height() == 720 + assert app.width() == 1280 + assert len(app.findChildren(QPushButton)) == 20 + +def test_listLat(app,qtbot): + # cek jumlah latihan yang ditampilkan apakah berisi 16 latihan + assert len(app.listLat) == 16 + assert isinstance(app.findChild(QScrollArea), QScrollArea) + assert len(app.findChild(QScrollArea).findChildren(QPushButton)) == len(app.listLat) diff --git a/test/test_plan.py b/test/test_plan.py new file mode 100644 index 0000000000000000000000000000000000000000..497b813840d2f4930129f70075e945c5485010db --- /dev/null +++ b/test/test_plan.py @@ -0,0 +1,23 @@ +import pytest + +from PyQt6.QtCore import Qt, pyqtSignal +from PyQt6.QtGui import QPixmap, QCursor, QFont, QIcon +from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QScrollArea +import sys +import os + +path = os.getcwd() +sys.path.insert(0,f"{path}/src") +from plan import plan + +@pytest.fixture +def app(): + app = plan() + yield app + +def test_window(app,qtbot): + # cek window title + assert app.windowTitle() == "FitU - Plan" + assert app.height() == 720 + assert app.width() == 1280 + assert len(app.findChildren(QPushButton)) == 10 \ No newline at end of file diff --git a/test/test_plan2.py b/test/test_plan2.py new file mode 100644 index 0000000000000000000000000000000000000000..96e807235c931e5720e1cd5f2d59159ee4896437 --- /dev/null +++ b/test/test_plan2.py @@ -0,0 +1,41 @@ +import pytest +from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton +from PyQt6.QtCore import Qt, QTimer, QTime +import sys +import os + +path = os.getcwd() +sys.path.insert(0,f"{path}/src") +from plan2 import plan2 + +@pytest.fixture +def app(qtbot): + test_plan = plan2(1) + qtbot.addWidget(test_plan) + return test_plan + +def test_setUpPlan(app, qtbot): + assert app.nameLabel.text() == 'Push Up' + assert app.repLabel.text() == '' + assert app.timer_label.text() == '10 Rep' + assert app.currEx.movie().fileName() == 'img/exe-pushup.gif' + assert app.prevButton.isEnabled() == True + assert app.nextButton.isEnabled() == True + + qtbot.mouseClick(app.nextButton, Qt.MouseButton.LeftButton) + assert app.nameLabel.text() == 'Bridge' + assert app.currEx.movie().fileName() == 'img/exe-bridges.gif' + assert app.prevButton.isEnabled() == True + assert app.nextButton.isEnabled() == True + + qtbot.mouseClick(app.prevButton, Qt.MouseButton.LeftButton) + assert app.nameLabel.text() == 'Push Up' + assert app.currEx.movie().fileName() == 'img/exe-pushup.gif' + assert app.prevButton.isEnabled() == True + assert app.nextButton.isEnabled() == True + + qtbot.wait(2000) + assert app.remaining_time == 30 + + qtbot.wait(15000) + assert app.remaining_time == 30 diff --git a/test/test_register.py b/test/test_register.py new file mode 100644 index 0000000000000000000000000000000000000000..4d2a5b6b5e0b93058af496cbc0f177d9b98dfb30 --- /dev/null +++ b/test/test_register.py @@ -0,0 +1,79 @@ +import pytest +from PyQt6.QtWidgets import QApplication, QLineEdit, QRadioButton, QCheckBox, QPushButton +from PyQt6.QtCore import Qt + +import sys +import os + +path = os.getcwd() +sys.path.insert(0,f"{path}/src") +from register import register + +@pytest.fixture +def app(qtbot): + test_register = register() + qtbot.addWidget(test_register) + return test_register + +def test_name_input(app, qtbot): + name_input = app.nameInput + qtbot.keyClicks(name_input, "Test Name") + assert name_input.text() == "Test Name" + +def test_age_input(app, qtbot): + age_input = app.age + qtbot.keyClicks(age_input, "25") + assert age_input.text() == "25" + +def test_height_input(app, qtbot): + height_input = app.height + qtbot.keyClicks(height_input, "180") + assert height_input.text() == "180" + +def test_weight_input(app, qtbot): + weight_input = app.weight + qtbot.keyClicks(weight_input, "75") + assert weight_input.text() == "75" + +def test_gender_selection(app, qtbot): + male_button = app.male + female_button = app.female + + qtbot.mouseClick(male_button, Qt.MouseButton.LeftButton) + assert male_button.isChecked() + + qtbot.mouseClick(female_button, Qt.MouseButton.LeftButton) + assert female_button.isChecked() + +def test_body_type_selection(app, qtbot): + fit_checkbox = app.fit + thin_checkbox = app.thin + + qtbot.mouseClick(fit_checkbox, Qt.MouseButton.LeftButton) + assert fit_checkbox.isChecked() + + qtbot.mouseClick(thin_checkbox, Qt.MouseButton.LeftButton) + assert thin_checkbox.isChecked() + +def test_register_button(app, qtbot): + register_button = app.registerButton + name_input = app.nameInput + age_input = app.age + height_input = app.height + weight_input = app.weight + male_button = app.male + female_button = app.female + fit_checkbox = app.fit + thin_checkbox = app.thin + + # Input test data + qtbot.keyClicks(name_input, "Test Name") + qtbot.keyClicks(age_input, "25") + qtbot.keyClicks(height_input, "180") + qtbot.keyClicks(weight_input, "75") + qtbot.mouseClick(male_button, Qt.MouseButton.LeftButton) + qtbot.mouseClick(fit_checkbox, Qt.MouseButton.LeftButton) + + # Check if switch signal is emitted + # with qtbot.waitSignal(app.switch): + # qtbot.mouseClick(register_button, Qt.MouseButton.LeftButton)