@@ -151,6 +151,12 @@ def __init__(self):
151
151
)
152
152
self .appearance_mode_optionemenu .grid (row = 7 , column = 0 , padx = 20 , pady = (10 , 10 ))
153
153
154
+ # Define categories
155
+ self .categories = ["Work" , "Personal" , "Entertainment" , "Finance" , "Health" ]
156
+
157
+ # Add category selection in the password entry form
158
+ self .category_vars = {category : ctk .BooleanVar () for category in self .categories }
159
+
154
160
self .content_frame = ctk .CTkFrame (self )
155
161
self .content_frame .grid (row = 0 , column = 1 , sticky = "nsew" , padx = 20 , pady = 20 )
156
162
self .content_frame .grid_columnconfigure (0 , weight = 1 )
@@ -210,6 +216,12 @@ def add_password_form(self, pw_data=None):
210
216
button_frame = ctk .CTkFrame (form_frame )
211
217
button_frame .pack (fill = "x" , pady = (20 , 0 ))
212
218
219
+ category_frame = ctk .CTkFrame (self .content_frame )
220
+ category_frame .pack (pady = (10 , 0 ))
221
+
222
+ for category , var in self .category_vars .items ():
223
+ ctk .CTkCheckBox (category_frame , text = category , variable = var ).pack (side = "left" , padx = 5 )
224
+
213
225
if pw_data is None :
214
226
ctk .CTkButton (
215
227
button_frame , text = "Generate Password" , command = self .generate_password
@@ -272,17 +284,31 @@ def generate_password(self):
272
284
273
285
def save_password (self ):
274
286
data = {key : widget .get () for key , widget in self .entrywid .items ()}
287
+
288
+ selected_categories = [cat for cat , var in self .category_vars .items () if var .get ()]
289
+
290
+ if not all (data .values ()) or not selected_categories :
291
+ msgbox .showwarning ("Missing Information" , "All fields must be filled, and at least one category must be selected." )
292
+ return
293
+
294
+ data ['category' ] = ', ' .join (selected_categories )
295
+
275
296
276
297
if not all (data .values ()):
277
298
msgbox .showwarning ("Missing Information" , "All fields must be filled!" )
278
-
279
299
elif not is_valid_email (data ['email' ]):
280
300
msgbox .showwarning ("Invalid Email" , "Invalid email format. Please enter a valid email address." )
281
301
elif not is_valid_username (data ['username' ]):
282
302
msgbox .showwarning ("Invalid Username" , "Username can only contain alphanumeric characters, dots, or underscores." )
283
303
elif not is_valid_website_url (data ['website' ]):
284
304
msgbox .showwarning ("Invalid Website URL" , "Website URL should be in format https://www.[websitename].[websitedomain]" )
285
305
else :
306
+ existing_passwords = db .get_all_passwords ()
307
+ for entry in existing_passwords :
308
+ if entry [1 ] == data ['email' ]:
309
+ msgbox .showwarning ("Duplicate Entry" , "This email already exists for this website. Please edit existing email or add another email." )
310
+ return
311
+
286
312
strng = password_strength (data ["password" ])
287
313
288
314
for widget in self .content_frame .winfo_children ():
@@ -382,6 +408,15 @@ def search_passwords(self):
382
408
side = "left"
383
409
)
384
410
411
+ self .categories = ['Work' , 'Personal' , 'Entertainment' , 'Finance' , 'Other' ]
412
+ self .category_vars = {category : ctk .BooleanVar () for category in self .categories }
413
+ self .category_frame = ctk .CTkFrame (self .content_frame )
414
+ self .category_frame .pack (pady = (10 , 20 ))
415
+
416
+ for category , var in self .category_vars .items ():
417
+ ctk .CTkCheckBox (self .category_frame , text = category , variable = var ).pack (side = "left" )
418
+
419
+
385
420
self .search_results_frame = ctk .CTkScrollableFrame (self .content_frame )
386
421
self .search_results_frame .pack (expand = True , fill = "both" , padx = 20 , pady = (0 , 20 ))
387
422
@@ -390,11 +425,17 @@ def search_passwords(self):
390
425
391
426
def perform_search (self ):
392
427
query = self .search_entry .get ()
393
- if not query :
394
- msgbox .showwarning ("Warning" , "Please Enter A Search Query!" )
428
+ selected_categories = [category for category , var in self .category_vars .items () if var .get ()]
429
+
430
+ if not query and not selected_categories :
431
+ msgbox .showwarning ("Warning" , "Please enter a search query or select at least one category!" )
395
432
return
396
433
397
- self .search_results = db .search_passwords (query )
434
+ if query :
435
+ self .search_results = db .search_passwords (query , selected_categories )
436
+ else :
437
+ self .search_results = db .search_passwords_by_categories (selected_categories )
438
+
398
439
self .current_page = 0
399
440
400
441
if not self .search_results :
@@ -642,6 +683,15 @@ def edit_password(self, pw_data):
642
683
def update_password (self , old_data ):
643
684
new_data = {key : widget .get () for key , widget in self .entrywid .items ()}
644
685
686
+ # Get selected categories from checkboxes
687
+ selected_categories = [cat for cat , var in self .category_vars .items () if var .get ()]
688
+
689
+ if not all (new_data .values ()) or not selected_categories :
690
+ msgbox .showwarning ("Missing Information" , "All fields must be filled, and at least one category must be selected." )
691
+ return
692
+
693
+ new_data ['category' ] = ', ' .join (selected_categories )
694
+
645
695
if not all (new_data .values ()):
646
696
msgbox .showwarning ("Missing Information" , "All fields must be filled!" )
647
697
@@ -653,6 +703,11 @@ def update_password(self, old_data):
653
703
msgbox .showwarning ("Invalid Website URL" , "Website URL should be in format https://www.[websitename].[websitedomain]" )
654
704
655
705
else :
706
+ existing_passwords = db .get_all_passwords ()
707
+ for entry in existing_passwords :
708
+ if entry [0 ] == new_data ['website' ] and entry [1 ] == new_data ['email' ] and entry != old_data :
709
+ msgbox .showwarning ("Duplicate Entry" , "This email already exists for this website. Please edit the existing entry or use a different email." )
710
+ return
656
711
try :
657
712
db .update_password (old_data , new_data )
658
713
self .clear_entries ()
0 commit comments