33import javax .swing .*;
44import java .awt .event .ActionEvent ;
55import java .awt .event .ActionListener ;
6- import javax .sound .sampled .*;
7- import java .net .URL ;
8- import java .io .File ;
9- import java .io .FileInputStream ;
10- import java .io .InputStream ;
116import java .util .Timer ;
127import java .util .TimerTask ;
138
149public class App {
10+ private JMenuBar menubar ;
1511 private JPanel panelMain ;
1612 private JButton buttonStart ;
1713 private JButton buttonStop ;
1814 private JLabel labelMsg ;
1915 private JLabel labelTimer ;
2016 private JPanel panelButtons ;
2117 private long focusMinutes ;
22- private static final JFrame frame = new JFrame ( "App" ) ;
18+ private JFrame frame ;
2319
2420 enum State {
2521 BOOTED ,
@@ -76,27 +72,6 @@ public boolean isTimerStopped() {
7672 }
7773 // END SETTERS AND GETTERS
7874
79- // Transform the remaining time to a human-readable format.
80- public String convertMillisToMinutes (long millis , long periodOfTime ) {
81- long selectedLength = periodOfTime * 60 * 1000 ;
82- long remainingTime = selectedLength - millis ;
83- long millisToSeconds = (remainingTime / 1000 ) % 60 ;
84- long millisToMinutes = remainingTime / (1000 * 60 );
85-
86- if (remainingTime <= 0 ) {
87- return "00:00" ;
88- }
89-
90- return String .format ("%02d" , millisToMinutes ) + ":" + String .format ("%02d" , millisToSeconds );
91- }
92-
93- private void startFocusPeriod () {
94- setLabelMsg (Locale .FOCUS_MESSAGE );
95- setEnableButtonStop (true );
96- setEnableButtonStart (false );
97- setTimerStopped (false );
98- }
99-
10075 // Creates a dialogue that asks the user for the focus period.
10176 private void requestFocusTime () {
10277 String m = JOptionPane .showInputDialog (Locale .TIME_QUESTION_MESSAGE );
@@ -105,28 +80,44 @@ private void requestFocusTime() {
10580 try {
10681 convertedMinutes = Integer .parseInt (m );
10782 } catch (Exception exception ) {
108- convertedMinutes = 30 ;
83+ convertedMinutes = 25 ;
10984 }
11085
11186 if (convertedMinutes < 1 || convertedMinutes > 60 ) {
112- convertedMinutes = 30 ;
87+ convertedMinutes = 25 ;
11388 }
11489 setFocusMinutes (convertedMinutes );
11590 }
11691
117- private void endFocusPeriod () {
118- setState (State .BREAK );
119-
120- setLabelMsg (Locale .FOCUS_DONE_MESSAGE );
92+ // Edits the message and the timer labels.
93+ private void resetTimerAndMessage (String message ) {
94+ setLabelMsg (message );
12195 setEnableButtonStart (true );
12296 setEnableButtonStop (false );
12397 setTimerStopped (false );
12498 setLabelTimer ("00:00" );
99+ }
125100
126- flashWindow ();
127- playAlarmSound ();
101+ public void finishSessionAndDisplayMessage (String message , JFrame frame ) {
102+ flashWindow (frame );
103+ Utils .playAlarmSound ();
128104
129- JOptionPane .showMessageDialog (null , Locale .FOCUS_DONE_MESSAGE_ALERT );
105+ JOptionPane .showMessageDialog (null , message );
106+ }
107+
108+ private void startFocusPeriod () {
109+ setLabelMsg (Locale .FOCUS_MESSAGE );
110+ setEnableButtonStop (true );
111+ setEnableButtonStart (false );
112+ setTimerStopped (false );
113+ }
114+
115+ private void endFocusPeriod () {
116+ // Ended the focus, we need to take a break now.
117+ setState (State .BREAK );
118+
119+ resetTimerAndMessage (Locale .FOCUS_DONE_MESSAGE );
120+ finishSessionAndDisplayMessage (Locale .FOCUS_DONE_MESSAGE_ALERT , frame );
130121 }
131122
132123 private void startBreakPeriod () {
@@ -137,106 +128,133 @@ private void startBreakPeriod() {
137128 }
138129
139130 private void endBreakPeriod () {
131+ // Ended the break, we need to now.
140132 setState (State .FOCUS );
141133
142- setLabelMsg (Locale .BREAK_DONE_MESSAGE );
143- setEnableButtonStart (true );
144- setEnableButtonStop (false );
145- setTimerStopped (false );
146- setLabelTimer ("00:00" );
147-
148- flashWindow ();
149- playAlarmSound ();
150-
151- JOptionPane .showMessageDialog (null , Locale .BREAK_DONE_MESSAGE_ALERT );
134+ resetTimerAndMessage (Locale .BREAK_DONE_MESSAGE );
135+ finishSessionAndDisplayMessage (Locale .BREAK_DONE_MESSAGE_ALERT , frame );
152136 }
153137
154- private static void flashWindow () {
138+ public static void flashWindow (JFrame frame ) {
155139 frame .setAlwaysOnTop (true );
156140 frame .toFront ();
157141 frame .requestFocus ();
158142 frame .setAlwaysOnTop (false );
159143 }
160144
161- private void playAlarmSound () {
162- URL url = this .getClass ().getClassLoader ().getResource ("alarm.wav" );
163- try {
164- assert url != null ;
165- AudioInputStream audioIn = AudioSystem .getAudioInputStream (url );
166- Clip clip = AudioSystem .getClip ();
145+ private void startTimerTask () {
146+ long startTime = System .currentTimeMillis ();
147+ Timer timer = new Timer ();
167148
168- clip .open (audioIn );
169- clip .start ();
149+ // Pick whether we choose to subtract from session or break time.
150+ long sessionMinutes = 0 ;
151+ if (getState () == State .BOOTED || getState () == State .FOCUS ) {
152+ sessionMinutes = getFocusMinutes ();
170153 }
171- catch ( Exception e ) {
172- System . out . println ( e . getMessage () );
154+ else if ( getState () == State . BREAK ) {
155+ sessionMinutes = getBreakMinutes ( );
173156 }
157+
158+ long finalSessionMinutes = sessionMinutes ;
159+ timer .scheduleAtFixedRate (new TimerTask () {
160+ @ Override
161+ public void run () {
162+ long systemTime = System .currentTimeMillis ();
163+
164+ // If the timer is below zero, or it has been stopped, cancel the updates.
165+ if (systemTime - startTime > finalSessionMinutes * 60 * 1000 || isTimerStopped ()) {
166+ this .cancel ();
167+ if (getState () == State .BOOTED || getState () == State .FOCUS ) {
168+ endFocusPeriod ();
169+ }
170+ else if (getState () == State .BREAK ) {
171+ endBreakPeriod ();
172+ }
173+ }
174+ // Update the timer with the new remaining time.
175+ else {
176+ setLabelTimer (Utils .convertRemainingMillisToMinutes (systemTime - startTime , getFocusMinutes ()));
177+ }
178+ }
179+ }, 0 , 100 );
180+ }
181+
182+ private void initFrame (JFrame frame ) {
183+ frame .toFront ();
184+ frame .setContentPane (this .panelMain );
185+ frame .setDefaultCloseOperation (JFrame .EXIT_ON_CLOSE );
186+ frame .pack ();
187+ frame .setVisible (true );
188+ frame .setResizable (false );
189+ frame .setTitle ("Pomodoro app" );
190+ frame .setLocationRelativeTo (null );
191+ frame .setSize (350 , 250 );
192+ }
193+
194+ private void initMenuBar (JMenuBar menubar , JFrame frame ) {
195+ JMenuItem aboutItem = new JMenuItem ("About" );
196+ JMenuItem usageItem = new JMenuItem ("Usage" );
197+ JMenu helpMenu = new JMenu ("Help" );
198+
199+ aboutItem .addActionListener (new ActionListener () {
200+ @ Override
201+ public void actionPerformed (ActionEvent e ) {
202+ JOptionPane .showMessageDialog (null , Locale .ABOUT_MESSAGE );
203+ }
204+ });
205+
206+ usageItem .addActionListener (new ActionListener () {
207+ @ Override
208+ public void actionPerformed (ActionEvent e ) {
209+ JOptionPane .showMessageDialog (null , Locale .USAGE_MESSAGE );
210+ }
211+ });
212+
213+ helpMenu .add (aboutItem );
214+ helpMenu .add (usageItem );
215+ menubar .add (helpMenu );
216+ frame .setJMenuBar (menubar );
174217 }
175218
176219 public App () {
220+ this .frame = new JFrame ();
221+ initFrame (this .frame );
222+
223+ this .menubar = new JMenuBar ();
224+ initMenuBar (this .menubar , this .frame );
225+
177226 // Start button logic
178227 buttonStart .addActionListener (new ActionListener () {
179228 @ Override
180229 public void actionPerformed (ActionEvent e ) {
230+ Utils .playClickSound ();
231+
181232 if (getState () == State .FOCUS || getState () == State .BOOTED ) {
182233 // Only request the focus time the first time.
183234 if (getState () == State .BOOTED )
184235 requestFocusTime ();
185236 startFocusPeriod ();
186237
187- long startTime = System .currentTimeMillis ();
188- Timer timer = new Timer ();
189- timer .scheduleAtFixedRate (new TimerTask () {
190- @ Override
191- public void run () {
192- long systemTime = System .currentTimeMillis ();
193- if (systemTime - startTime > getFocusMinutes () * 60 * 1000 || isTimerStopped ()) {
194- this .cancel ();
195- endFocusPeriod ();
196- } else {
197- setLabelTimer (convertMillisToMinutes (systemTime - startTime , getFocusMinutes ()));
198- }
199- }
200- }, 0 , 100 );
238+ startTimerTask ();
201239 }
202240 else if (getState () == State .BREAK ) {
203241 startBreakPeriod ();
204242
205- long startTime = System .currentTimeMillis ();
206- Timer timer = new Timer ();
207- timer .scheduleAtFixedRate (new TimerTask () {
208- @ Override
209- public void run () {
210- long systemTime = System .currentTimeMillis ();
211- if (systemTime - startTime > getBreakMinutes () * 60 * 1000 || isTimerStopped ()) {
212- this .cancel ();
213- endBreakPeriod ();
214- } else {
215- setLabelTimer (convertMillisToMinutes (systemTime - startTime , getBreakMinutes ()));
216- }
217- }
218- }, 0 , 100 );
243+ startTimerTask ();
219244 }
220245 }
221246 });
222247 buttonStop .addActionListener (new ActionListener () {
223248 @ Override
224249 public void actionPerformed (ActionEvent e ) {
250+ Utils .playClickSound ();
251+
225252 setTimerStopped (true );
226253 }
227254 });
228255 }
229256
230257 public static void main (String [] args ) {
231- // Init settings
232- frame .toFront ();
233- frame .setContentPane (new App ().panelMain );
234- frame .setDefaultCloseOperation (JFrame .EXIT_ON_CLOSE );
235- frame .pack ();
236- frame .setVisible (true );
237- frame .setResizable (false );
238- frame .setTitle ("Pomodoro app" );
239- frame .setLocationRelativeTo (null );
240- frame .setSize (350 , 225 );
258+ new App ();
241259 }
242260}
0 commit comments