Panel Navigation System
MegaDownloader uses Java Swing’s CardLayout to implement single-window navigation between multiple panels. This approach provides a seamless user experience without opening multiple windows.
CardLayout Implementation
Location : Main.java:72-78
// Setup CardLayout
cardLayout = new java. awt . CardLayout ();
cardPanel = new javax. swing . JPanel (cardLayout);
cardPanel . add (mainPanel, "MAIN" );
cardPanel . add (preferencesPanel, "PREFERENCES" );
cardPanel . add (manageMediaPanel, "MEDIA" );
cardPanel . add (loginForm, "LOGIN" );
Each panel is registered with a string identifier that’s used for navigation.
Navigation State Management
The Main class tracks navigation state to enable back button functionality:
private String currentPanel = "LOGIN" ;
private String previousPanel = "LOGIN" ;
public void showMainPanel () {
previousPanel = currentPanel;
currentPanel = "MAIN" ;
cardLayout . show (cardPanel, "MAIN" );
}
public void goBack () {
cardLayout . show (cardPanel, previousPanel);
currentPanel = previousPanel;
}
Navigation Flow
Application Start Flow
Code : Main.java:109-119
// Check if config.txt exists on startup
checkConfig ();
// Try auto-login
if ( loginForm . checkAutoLogin ()) {
currentPanel = "MAIN" ;
cardLayout . show (cardPanel, "MAIN" );
} else {
currentPanel = "LOGIN" ;
cardLayout . show (cardPanel, "LOGIN" );
}
Login to Main Flow
Code : LoginForm.java:194-245
Navigation Between Panels
UI Layout
Location : LoginForm.java:73-152
Components
Layout
Keyboard Shortcuts
Email text field with validation
Password field
“Remember me” checkbox
Login button
Banner image
Uses BoxLayout with CENTER alignment: JPanel formPanel = new JPanel ();
formPanel . setLayout ( new BoxLayout (formPanel, BoxLayout . Y_AXIS ));
formPanel . add (lblPhotoBanner);
formPanel . add (lblEmail);
formPanel . add (txtEmail);
formPanel . add (lblPassword);
formPanel . add (txtPassword);
formPanel . add (tglRemember);
formPanel . add (btnLogin);
ENTER : Submit login form
ESC : Exit application
Real-time Email Validation
Location : LoginForm.java:96-113
txtEmail . getDocument (). addDocumentListener ( new DocumentListener () {
@ Override
public void insertUpdate ( DocumentEvent e ) {
validateEmail ();
}
// ... other methods
});
private boolean validateEmail () {
String email = txtEmail . getText ();
Pattern pattern = Pattern . compile ( "^[ \\ w.-]+@[ \\ w.-]+ \\ .[a-zA-Z]{2,}$" );
if ( ! pattern . matcher (email). matches ()) {
txtEmail . setBorder ( BorderFactory . createLineBorder ( new Color ( 220 , 53 , 69 )));
return false ;
}
txtEmail . setBorder (defaultBorder);
return true ;
}
The email field shows a red border when the input doesn’t match the email pattern.
Session Persistence
Credentials are stored using Java Preferences API:
prefs = Preferences . userNodeForPackage ( LoginForm . class );
// Save on successful login
if ( tglRemember . isSelected ()) {
prefs . put ( "auth_token" , token);
prefs . put ( "user_email" , email);
}
// Auto-login on startup
public boolean checkAutoLogin () {
String savedToken = prefs . get ( "auth_token" , null );
if (savedToken != null && mediaPollingComponent . checkToken (savedToken)) {
return true ;
}
return false ;
}
MainPanel - Download Interface
UI Layout
Location : MainPanel.java:331-469
Main Components
URL input field
Download button
Audio-only checkbox
Progress bar (hidden initially)
Play button (appears after download)
Additional Features
Advanced options toggle
Custom arguments text area
Manage Media button
GitHub logo (clickable link)
Logout button
Advanced Options Toggle
Location : MainPanel.java:785-796
private void tglAdvancedOptionsActionPerformed ( java . awt . event . ActionEvent evt) {
boolean isSelected = tglAdvancedOptions . isSelected ();
jScrollPane1 . setVisible (isSelected);
txtAreaCustomArgs . setVisible (isSelected);
lblCustomArgs . setVisible (isSelected);
if (isSelected) {
tglAdvancedOptions . setText ( "Advanced ▲" );
} else {
tglAdvancedOptions . setText ( "Advanced ▼" );
}
}
Users can add custom yt-dlp arguments like: --format best
--write-thumbnail
--embed-metadata
These are parsed and added to the yt-dlp command: String [] args = customArgs . split ( " \\ s+(?=(?:[^ \" ]* \" [^ \" ]* \" )*[^ \" ]*$)" );
for ( String arg : args) {
command . add (arg);
}
Download Progress Indicator
Location : MainPanel.java:540-544
downloadBtn . setEnabled ( false );
downloadBtn . setText ( "Downloading..." );
progressBar . setValue ( 0 );
progressBar . setVisible ( true );
Progress is parsed from yt-dlp output:
if ( line . contains ( "[download]" ) && line . contains ( "%" )) {
String percentStr = line . substring (
line . indexOf ( "]" ) + 1 , line . indexOf ( "%" )). trim ();
double percent = Double . parseDouble (percentStr);
publish (( int ) percent);
}
Keyboard Shortcuts
Location : MainPanel.java:158-168
ESC : Exit application immediately
UI Layout
Location : ManageMediaPanel.java:694-750
Table Columns
Controls
Quick Actions
Status - Sync indicator (✓ for both, empty for local/server only)
File Name - Media filename
Type - Video/Audio/Other
Size - Formatted file size (KB/MB/GB)
Date Modified - Last modification date
Source - Local/Server/Both
Text filter field (real-time search)
Type filter combo box (All/Video/Audio)
Quick Actions list
Exit button
Play - Open file with default player
Open Folder - Open download directory
Download - Download from server
Delete - Remove local file
Sortable Table
tblFiles . setAutoCreateRowSorter ( true );
Users can click column headers to sort the table by any column.
Location : ManageMediaPanel.java:309-347
tableContextMenu = new JPopupMenu ();
JMenuItem playItem = new JMenuItem ( "Play" );
JMenuItem openFolderItem = new JMenuItem ( "Open Folder" );
JMenuItem downloadItem = new JMenuItem ( "Download" );
JMenuItem deleteItem = new JMenuItem ( "Delete" );
tblFiles . addMouseListener ( new MouseAdapter () {
@ Override
public void mouseReleased ( MouseEvent e ) {
if ( e . isPopupTrigger ()) {
int row = tblFiles . rowAtPoint ( e . getPoint ());
tblFiles . setRowSelectionInterval (row, row);
tableContextMenu . show ( e . getComponent (), e . getX (), e . getY ());
}
}
});
Real-time Text Filter
Location : ManageMediaPanel.java:284-307
fieldFilter . getDocument (). addDocumentListener ( new DocumentListener () {
private void updateTextFilter () {
textFilter = fieldFilter . getText (). toLowerCase (). trim ();
loadMediaFiles (); // Refresh table
}
});
Filters both local and server files:
if ( textFilter . isEmpty () ||
media . getFileName (). toLowerCase (). contains (textFilter)) {
// Add to table
}
Refresh on Panel Show
Location : ManageMediaPanel.java:272-279
addComponentListener ( new ComponentAdapter () {
@ Override
public void componentShown ( ComponentEvent e ) {
loadMediaFiles ();
}
});
The media table automatically refreshes every time the panel is displayed.
PreferencesPanel - Settings
UI Layout
Location : PreferencesPanel.java:176-317
Path Configuration
yt-dlp location with file chooser
Download directory selection
Current paths display
Download Options
Speed limiter toggle and slider
Speed text field (manual input)
M3U playlist generation checkbox
Speed Limiter Controls
Location : PreferencesPanel.java:70-123
The slider and text field are synchronized:
// Slider updates text field
sliderLimiter . addChangeListener ( new ChangeListener () {
@ Override
public void stateChanged ( ChangeEvent e ) {
speedLimitKBps = sliderLimiter . getValue ();
txtLimiter . setText (speedLimitKBps + " KB/s" );
}
});
// Text field updates slider
txtLimiter . getDocument (). addDocumentListener ( new DocumentListener () {
private void updateSliderFromText () {
String text = txtLimiter . getText (). replaceAll ( "[^0-9]" , "" );
int value = Math . max ( 1 , Math . min ( 100000 , Integer . parseInt (text)));
sliderLimiter . setValue (value);
}
});
Range : 1 KB/s to 100,000 KB/s (100 MB/s)
File Choosers
yt-dlp Executable (PreferencesPanel.java:327):
JFileChooser fileChooser = new JFileChooser ();
fileChooser . setDialogTitle ( "Select yt-dlp executable" );
fileChooser . setFileSelectionMode ( JFileChooser . FILES_ONLY );
FileNameExtensionFilter filter = new FileNameExtensionFilter ( "Executable" , "exe" );
fileChooser . setFileFilter (filter);
Download Directory (PreferencesPanel.java:372):
JFileChooser fileChooser = new JFileChooser ();
fileChooser . setDialogTitle ( "Select download directory" );
fileChooser . setFileSelectionMode ( JFileChooser . DIRECTORIES_ONLY );
Window Dragging
Since the application uses an undecorated frame (no title bar), custom dragging is implemented:
Implementation
Location : Main.java:139-164
private Point initialClick ;
private void enableDragging ( Component component) {
component . addMouseListener ( new MouseAdapter () {
@ Override
public void mousePressed ( MouseEvent e ) {
initialClick = e . getPoint ();
}
});
component . addMouseMotionListener ( new MouseMotionAdapter () {
@ Override
public void mouseDragged ( MouseEvent e ) {
int thisX = Main . this . getLocation (). x ;
int thisY = Main . this . getLocation (). y ;
int xMoved = e . getX () - initialClick . x ;
int yMoved = e . getY () - initialClick . y ;
Main . this . setLocation (thisX + xMoved, thisY + yMoved);
}
});
}
Applied To
enableDragging ( getContentPane ());
enableDragging (jMenuBar1);
enableDragging (mediaPollingComponent);
Users can drag the window by clicking on the content pane, menu bar, or media polling component.
FlatLaf Darcula Theme
Theme Setup
Location : Main.java:50
public Main () {
FlatDarculaLaf . setup ();
setUndecorated ( true );
initComponents ();
// ...
}
FlatLaf Darcula provides a modern, dark look and feel that’s automatically applied to all Swing components.
Key Visual Features
Dark background color scheme
Modern button styling
Flat design aesthetic
Improved contrast and readability
Custom component rendering
The exit button is placed in the top layer using JLayeredPane:
Location : Main.java:87
layeredPane . add (btnExit, JLayeredPane . POPUP_LAYER );
btnExit . setBounds ( 770 , 2 , 26 , 26 );
This ensures the exit button is always visible regardless of which panel is active.
Location : Main.java:268-270
private void btnExitActionPerformed ( java . awt . event . ActionEvent evt) {
System . exit ( 0 );
}
Navigation Summary
Panel Transitions
From LoginForm → MainPanel (on successful login)
From MainPanel → PreferencesPanel (menu)
→ ManageMediaPanel (button)
→ LoginForm (logout)
From PreferencesPanel → Previous panel (back button or ESC)
From ManageMediaPanel → MainPanel (exit button or ESC)
Keyboard Navigation
ESC on LoginForm: Exit application
ENTER on LoginForm: Submit login
ESC on MainPanel: Exit application
ESC on PreferencesPanel: Go back to previous panel
ESC on ManageMediaPanel: Return to MainPanel
Keyboard shortcuts are implemented using InputMap and ActionMap with JComponent.WHEN_IN_FOCUSED_WINDOW scope.