Have a summary of Non-AFK times

Have a summary page that can give an overview over a long period.
So you can use it to track your work time.

E.g. an output can look like this:

╔═══════════╤══════════════════════════════════════════════════════════════════════════════════════════════════╗
║           │ 00  01  02  03  04  05  06  07  08  09  10  11  12  13  14  15  16  17  18  19  20  21  22  23   ║
╟───────────┼── week 23 ───────────────────────────────────────────────────────────────────────────────────────╢
║ 09.06 Fr. │ .   .   .   .   .   .   .   .   .   .   .   .   .   .   .###.  ###  ##  . ###   .   .   .   .    ║
║ 10.06 Sa. │ .   .   .   .   .   .   .   .########   .## ## #.   .#####  .###.   .   .   .   .   .   .   .    ║
║ 11.06 So. │ .   .   .   .   .   .   . ###  ######  ##   .  #####. ####  .   .   .   .   ##  .   .   .   .    ║
╟───────────┼── week 24 ───────────────────────────────────────────────────────────────────────────────────────╢
║ 12.06 Mo. │ .   .   .   .   .   .   .   . ###   ####### ##  ##  ####.# ## ### ##.   ##  #   .   .   .   .    ║
║ 13.06 Di. │ .   .   .   .   .   .   . ####  .   .   .   .   .   .   .   .   .   .#  .   .###### .   .   .    ║
║ 14.06 Mi. │ .   .   .   .   .   .   .###.# #### #   .   .   .   .   .   .   .   .   .   .   .   .   .   .    ║
║ 15.06 Do. │ .   .   .   .   .   .###### .   .   ##### ##.####   ###### ###  ####.   ## ###  .   .   .   .    ║
║ 16.06 Fr. │ .   .   .   .   .   .   .   ############## ##   .   ### .## #  ###  .   .  #####.   .########    ║
║ 17.06 Sa. │ .   .   .   .   .   .   .   .   .   . ##. # .   .   .   .   .   .   .   .   .   # ####  .   .    ║
║ 18.06 So. │ .   .   .   .   .   .   .   .   .###.   .   .   .   .   .   .   .   .   .   .   .   .   .   .    ║
╚═══════════╧══════════════════════════════════════════════════════════════════════════════════════════════════╝

I created this by a Java command line tool aggregating the CSV export. However it would be great to have it in the UI directly.
Here my tool:

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.TextStyle;
import java.time.temporal.ChronoUnit;
import java.time.temporal.IsoFields;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

public class AfkCalendar {

    final int QUATER_HOURS_SECONDS = 60*15;
    private String[] args;
    private Map<LocalDate, ArrayList<Integer>> data = new TreeMap<>();
    
    public AfkCalendar(String[] args) {
        this.args = args;
    }

    public static void main(String[] args) throws IOException {
        var proc = new AfkCalendar(args);
        proc.run();
    }

    private void run() throws IOException {
        System.out.println(args[0]);
        
        try( var rd = Files.newBufferedReader(Paths.get(args[0]))){
            var title = rd.readLine();
            if( !"timestamp,duration,status".equals(title)) {
                System.out.println("Unexpected title: "+title);
                return;
            }
                
            String line = null;
            while( (line = rd.readLine()) != null ) {
                var parts = line.split(",");
                var timeStr = parts[0];
                var durStr = parts[1];
                var afk = parts[2];
                if( !"not-afk".equals(afk)) {
                    continue;
                }
                
                var dateTime = ZonedDateTime.parse(timeStr)
                        .withZoneSameInstant(ZoneId.systemDefault())
                        .toLocalDateTime();
                var durationRemaining = new BigDecimal(durStr)
                        .intValue();
                var quaterRemaining = QUATER_HOURS_SECONDS 
                        - (dateTime.toLocalTime().toSecondOfDay() % QUATER_HOURS_SECONDS);
                
                var quaterValues = new ArrayList<Integer>();
                while( durationRemaining > 0 ) {
                    var quater = Math.min(quaterRemaining, durationRemaining);
                    quaterValues.add(quater);
                    durationRemaining -= quater;
                    quaterRemaining = QUATER_HOURS_SECONDS;
                    
                    var date = dateTime.toLocalDate();
                    var time = dateTime.toLocalTime();
                    var quaterIndex = time.getHour() * 4
                            + time.getMinute() / 15;
                    
                    var quaterList = data.computeIfAbsent(date, k -> createDayQuaters());
                    var value = quaterList.get(quaterIndex).intValue();
                    value += quater;
                    quaterList.set(quaterIndex, value);
                    
                    dateTime = dateTime.plus(QUATER_HOURS_SECONDS, ChronoUnit.SECONDS);
                }
            }
        }
        System.out.println("╔═══════════╤══════════════════════════════════════════════════════════════════════════════════════════════════╗");
        System.out.println("║           │ 00  01  02  03  04  05  06  07  08  09  10  11  12  13  14  15  16  17  18  19  20  21  22  23   ║");
        int week = -1;
        for( var entry : data.entrySet()) {
            var date = entry.getKey();
            var quaters = entry.getValue();
            int thisWeek = date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR );
            if( week != thisWeek) {
                week = thisWeek;
                System.out.printf("╟───────────┼── week %2d ───────────────────────────────────────────────────────────────────────────────────────╢%n", week );
            }
            StringBuilder sb = new StringBuilder();
            sb.append(String.format("║ %02d.%02d %s │ ", date.getDayOfMonth(), date.getMonthValue(), getDayOfWeek(date)));
            for( int i = 0; i < quaters.size(); i++  ) {
                var quater = quaters.get(i);
                if( quater.intValue() >= QUATER_HOURS_SECONDS/2 )
                    sb.append( "#");
                else if( i % 4 == 0 )
                    sb.append( ".");
                else
                    sb.append( " ");
            }
            sb.append( " ║");
            System.out.println(sb);
        }
        System.out.println("╚═══════════╧══════════════════════════════════════════════════════════════════════════════════════════════════╝");
    }

    private ArrayList<Integer> createDayQuaters(){
        int QUATERS_PER_DAY = 24*4;
        var res = new ArrayList<Integer>(QUATERS_PER_DAY);
        for( int i = 0; i < QUATERS_PER_DAY; i++ )
            res.add(0);
        return res;
    }

    private String getDayOfWeek(LocalDate date) {
        return date.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.getDefault());
    }
}