Generally, the loop method should not delay. This means that it runs in a few microseconds.
Look at it this way: each time loop() runs, it has to ask and answer the question: "is there anything I need to do right now". Or, to put it another way, "has anything in the world changed since the last time I was executed?" In the case of this sketch, there are two important things that might change: millis() can tick over, and pin 22 might change state.
so, loop() looks like this:
byte state_of_pin_22_last_time_i_executed;
int which_light_is_currently_on;
uint32_t time_at_which_the_current_light_got_turned_on;
void loop() {
if pin 22 has changed from HIGH to LOW
do whatever I need to do to handle a button press
remember the new current state of pin 22
end
if it's now time to turn the current light off and the next one on
turn the current light off and the next one on
remember which light is now on and when I turned it on
end if
}