Før vi snur kalenderprosjektet

This commit is contained in:
ErolHaagenrud 2025-12-16 16:23:23 +01:00
parent 6f3fd9059d
commit 544cda4ce4
6 changed files with 98 additions and 174 deletions

View file

@ -27,7 +27,7 @@ public class CalendarFullFragment extends Fragment {
private RecyclerView recyclerView; private RecyclerView recyclerView;
private ProgressBar progressBar; private ProgressBar progressBar;
private TextView emptyView; private TextView emptyView;
private LinearLayoutManager layoutManager; // Trenger denne for å scrolle private LinearLayoutManager layoutManager;
@Nullable @Nullable
@Override @Override
@ -52,24 +52,25 @@ public class CalendarFullFragment extends Fragment {
private void fetchAllEvents() { private void fetchAllEvents() {
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
// Hent personlige hendelser ( med historikk) // Hent personlige hendelser
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext()); List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext());
// NYTT: Hent fra Google direkte // Hent felles hendelser fra WordPress Proxy (sikrer at vi får reminders)
String url = CalendarManager.getGoogleCalendarUrl(); RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
RetrofitClient.getApiService().getDirectGoogleEvents(url).enqueue(new Callback<GoogleCalendarModels.Response>() {
@Override @Override
public void onResponse(Call<GoogleCalendarModels.Response> call, Response<GoogleCalendarModels.Response> response) { public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
if (!isAdded()) return; if (!isAdded()) return;
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
List<CalendarEvent> apiEvents = new ArrayList<>(); List<CalendarEvent> apiEvents = new ArrayList<>();
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
// Konverter og formatér apiEvents = response.body();
apiEvents = CalendarManager.convertGoogleResponse(response.body()); // Formater data for visning
for (CalendarEvent e : apiEvents) {
CalendarManager.formatEventForUI(e);
}
} }
// Flett og vis
List<CalendarEvent> allEvents = CalendarManager.mergeAndSort(apiEvents, deviceEvents); List<CalendarEvent> allEvents = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
if (allEvents.isEmpty()) { if (allEvents.isEmpty()) {
@ -85,13 +86,12 @@ public class CalendarFullFragment extends Fragment {
}); });
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
// --- SCROLL TIL I DAG ---
scrollToToday(allEvents); scrollToToday(allEvents);
} }
} }
@Override @Override
public void onFailure(Call<GoogleCalendarModels.Response> call, Throwable t) { public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
if (!isAdded()) return; if (!isAdded()) return;
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
@ -114,7 +114,6 @@ public class CalendarFullFragment extends Fragment {
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
int scrollIndex = 0; int scrollIndex = 0;
// Finn første event som er i dag eller senere
for (int i = 0; i < events.size(); i++) { for (int i = 0; i < events.size(); i++) {
String raw = events.get(i).getRawDate(); String raw = events.get(i).getRawDate();
if (raw != null && raw.compareTo(today) >= 0) { if (raw != null && raw.compareTo(today) >= 0) {
@ -123,10 +122,9 @@ public class CalendarFullFragment extends Fragment {
} }
} }
// Scroll litt ned slik at "i dag" havner toppen, men ikke helt (offset 0)
// Bruker scrollToPositionWithOffset for presisjon
if (scrollIndex > 0) { if (scrollIndex > 0) {
layoutManager.scrollToPositionWithOffset(scrollIndex, 0); layoutManager.scrollToPositionWithOffset(scrollIndex, 0);
} }
} }
} }

View file

@ -4,7 +4,6 @@ import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.Cursor; import android.database.Cursor;
import android.provider.CalendarContract; import android.provider.CalendarContract;
import android.util.Log;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -15,96 +14,6 @@ import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
public class CalendarManager { public class CalendarManager {
// --- KONFIGURASJON FOR GOOGLE DIREKTE-KOBLING ---
private static final String GOOGLE_CALENDAR_ID = "kbservice.no_o2bmp5f9f540vedveit51optfo@group.calendar.google.com";
// TODO: Sett inn din API-nøkkel her!
private static final String GOOGLE_API_KEY = "AIzaSyCos8VW5mClUcuhs86gbSJo8uitY0fVPus";
public static String getGoogleCalendarUrl() {
long oneYearAgo = System.currentTimeMillis() - (365L * 24 * 60 * 60 * 1000);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String timeMin = dateFormat.format(new Date(oneYearAgo));
return "https://www.googleapis.com/calendar/v3/calendars/"
+ GOOGLE_CALENDAR_ID
+ "/events?key=" + GOOGLE_API_KEY
+ "&singleEvents=true"
+ "&orderBy=startTime"
+ "&maxResults=250"
+ "&timeMin=" + timeMin;
}
public static List<CalendarEvent> convertGoogleResponse(GoogleCalendarModels.Response response) {
List<CalendarEvent> events = new ArrayList<>();
if (response == null || response.items == null) return events;
for (GoogleCalendarModels.Item item : response.items) {
String title = item.summary != null ? item.summary : "(Uten tittel)";
String desc = item.description;
String loc = item.location;
// Dato-logikk
String start = null;
String end = null;
if (item.start != null) {
if (item.start.dateTime != null) start = item.start.dateTime;
else start = item.start.date;
}
if (item.end != null) {
if (item.end.dateTime != null) end = item.end.dateTime;
else end = item.end.date;
}
// --- SPY LOGGING (Se i Logcat etter KBS_DEBUG) ---
if (title.toLowerCase().contains("test")) {
Log.d("KBS_DEBUG", "--------------------------------------------------");
Log.d("KBS_DEBUG", "ANALYSERER EVENT: " + title);
Log.d("KBS_DEBUG", " Starttid: " + start);
if (item.reminders != null) {
Log.d("KBS_DEBUG", " useDefault: " + item.reminders.useDefault);
if (item.reminders.overrides != null && !item.reminders.overrides.isEmpty()) {
Log.d("KBS_DEBUG", " Fant " + item.reminders.overrides.size() + " overstyringer:");
for (GoogleCalendarModels.Override override : item.reminders.overrides) {
Log.d("KBS_DEBUG", " -> Metode: '" + override.method + "', Minutter: " + override.minutes);
}
} else {
Log.d("KBS_DEBUG", " Ingen 'overrides' (spesifikke varsler) funnet i listen fra Google.");
}
} else {
Log.d("KBS_DEBUG", " Ingen 'reminders'-seksjon funnet i JSON-responsen.");
}
Log.d("KBS_DEBUG", "--------------------------------------------------");
}
// -------------------------------------------------
// Varslings-logikk
int reminderMinutes = 15; // Default fallback
if (item.reminders != null) {
if (item.reminders.useDefault) {
reminderMinutes = 15;
} else if (item.reminders.overrides != null && !item.reminders.overrides.isEmpty()) {
// Vi tar den første vi finner for å se om det fanger opp dine 10/26 minutter
reminderMinutes = item.reminders.overrides.get(0).minutes;
}
}
CalendarEvent event = new CalendarEvent(title, start, end, desc, loc);
event.setReminderMinutes(reminderMinutes);
formatEventForUI(event);
events.add(event);
}
return events;
}
// --- RESTERENDE KODE (UENDRET) ---
private static List<String> getKbsCalendarIds(Context context) { private static List<String> getKbsCalendarIds(Context context) {
List<String> ids = new ArrayList<>(); List<String> ids = new ArrayList<>();
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
@ -209,6 +118,12 @@ public class CalendarManager {
} }
CalendarEvent event = new CalendarEvent(title, rawStart, rawEnd, desc, loc); CalendarEvent event = new CalendarEvent(title, rawStart, rawEnd, desc, loc);
// For lokale events bruker vi ikke reminderMinutes fra API,
// men systemet håndterer varsling selv for lokale kalendere.
// Vi setter den til 0 her for å unngå doble varsler fra appen.
event.setReminderMinutes(0);
formatEventForUI(event); formatEventForUI(event);
deviceEvents.add(event); deviceEvents.add(event);
} }
@ -296,4 +211,5 @@ public class CalendarManager {
return all; return all;
} }
} }

View file

@ -0,0 +1,4 @@
package com.kbs.kbsintranett;
public class CreateEventRequest {
}

View file

@ -37,17 +37,14 @@ public class HomeFragment extends Fragment {
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// Håndter svar kalendertillatelse
requestPermissionLauncher = registerForActivityResult( requestPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(), new ActivityResultContracts.RequestPermission(),
isGranted -> { isGranted -> {
// Prøv å laste kalender nytt ( potensielt med personlig kalender)
if (calendarRecycler != null) { if (calendarRecycler != null) {
fetchCalendarEvents(calendarRecycler); fetchCalendarEvents(calendarRecycler);
} }
} }
); );
// Start bakgrunnsjobb for varsling (kjører hver 15. minutt)
startNotificationWorker(); startNotificationWorker();
} }
@ -60,45 +57,38 @@ public class HomeFragment extends Fragment {
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
// 0. Profil-knapp
View profileBtn = view.findViewById(R.id.btn_profile); View profileBtn = view.findViewById(R.id.btn_profile);
if (profileBtn != null) { if (profileBtn != null) {
profileBtn.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.navigation_profile)); profileBtn.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.navigation_profile));
} }
// 1. Kalender oppsett
calendarRecycler = view.findViewById(R.id.recycler_calendar); calendarRecycler = view.findViewById(R.id.recycler_calendar);
calendarRecycler.setLayoutManager(new LinearLayoutManager(getContext())); calendarRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
// Sett tom adapter midlertidig
calendarRecycler.setAdapter(new CalendarAdapter(new ArrayList<>(), event -> {})); calendarRecycler.setAdapter(new CalendarAdapter(new ArrayList<>(), event -> {}));
// "Se alle" knapp for kalender
TextView viewAllCalendar = view.findViewById(R.id.btn_view_all_calendar); TextView viewAllCalendar = view.findViewById(R.id.btn_view_all_calendar);
if (viewAllCalendar != null) { if (viewAllCalendar != null) {
viewAllCalendar.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.action_home_to_calendarFull)); viewAllCalendar.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.action_home_to_calendarFull));
} }
// Sjekk tillatelse for personlig kalender
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) {
fetchCalendarEvents(calendarRecycler); fetchCalendarEvents(calendarRecycler);
} else { } else {
// Spør om lov til å lese kalender
requestPermissionLauncher.launch(Manifest.permission.READ_CALENDAR); requestPermissionLauncher.launch(Manifest.permission.READ_CALENDAR);
} }
// Spør også om lov til å sende varsler (Android 13+)
if (android.os.Build.VERSION.SDK_INT >= 33) { if (android.os.Build.VERSION.SDK_INT >= 33) {
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {}).launch(Manifest.permission.POST_NOTIFICATIONS); registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {}).launch(Manifest.permission.POST_NOTIFICATIONS);
} }
} }
// 2. Nyheter oppsett
RecyclerView newsRecycler = view.findViewById(R.id.recycler_news); RecyclerView newsRecycler = view.findViewById(R.id.recycler_news);
newsRecycler.setLayoutManager(new LinearLayoutManager(getContext())); newsRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
newsRecycler.setNestedScrollingEnabled(false); newsRecycler.setNestedScrollingEnabled(false);
// Sett tom adapter midlertidig
newsRecycler.setAdapter(new NewsAdapter(new ArrayList<>(), item -> {})); newsRecycler.setAdapter(new NewsAdapter(new ArrayList<>(), item -> {}));
// "Se alle" knapp for nyheter
TextView viewAllNews = view.findViewById(R.id.btn_view_all_news); TextView viewAllNews = view.findViewById(R.id.btn_view_all_news);
if (viewAllNews != null) { if (viewAllNews != null) {
viewAllNews.setOnClickListener(v -> { viewAllNews.setOnClickListener(v -> {
@ -110,26 +100,28 @@ public class HomeFragment extends Fragment {
} }
private void fetchCalendarEvents(RecyclerView recyclerView) { private void fetchCalendarEvents(RecyclerView recyclerView) {
// 1. Hent personlige hendelser først (fra CalendarManager) // 1. Hent personlige hendelser
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext()); List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext());
// 2. Hent API-hendelser DIREKTE fra Google // 2. Hent felles hendelser fra WordPress (Proxy mot Google)
String url = CalendarManager.getGoogleCalendarUrl(); RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
RetrofitClient.getApiService().getDirectGoogleEvents(url).enqueue(new Callback<GoogleCalendarModels.Response>() {
@Override @Override
public void onResponse(Call<GoogleCalendarModels.Response> call, Response<GoogleCalendarModels.Response> response) { public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
if (!isAdded()) return; if (!isAdded()) return;
List<CalendarEvent> apiEvents = new ArrayList<>(); List<CalendarEvent> apiEvents = new ArrayList<>();
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
// Konverter fra Google-modell til KBS-modell apiEvents = response.body();
apiEvents = CalendarManager.convertGoogleResponse(response.body()); // Formater datoer for visning (UI-logikk)
for (CalendarEvent e : apiEvents) {
CalendarManager.formatEventForUI(e);
}
} }
// 3. Flett listene (API + Personlig) og sorter // 3. Flett og sorter
List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents); List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
// 4. Filtrer ut hendelser som har passert (vis kun fremtidige + i dag) // 4. Filtrer (kun fremtidige + i dag)
List<CalendarEvent> upcomingEvents = new ArrayList<>(); List<CalendarEvent> upcomingEvents = new ArrayList<>();
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
@ -139,7 +131,7 @@ public class HomeFragment extends Fragment {
} }
} }
// 5. Vis kun de 5 første av de kommende // 5. Vis topp 5
List<CalendarEvent> top5 = new ArrayList<>(); List<CalendarEvent> top5 = new ArrayList<>();
for(int i=0; i<Math.min(upcomingEvents.size(), 5); i++) { for(int i=0; i<Math.min(upcomingEvents.size(), 5); i++) {
top5.add(upcomingEvents.get(i)); top5.add(upcomingEvents.get(i));
@ -152,9 +144,9 @@ public class HomeFragment extends Fragment {
} }
@Override @Override
public void onFailure(Call<GoogleCalendarModels.Response> call, Throwable t) { public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
if (!isAdded()) return; if (!isAdded()) return;
// Hvis API feiler, vis bare personlige events hvis vi har noen // Fallback til kun lokale events
if (!deviceEvents.isEmpty()) { if (!deviceEvents.isEmpty()) {
List<CalendarEvent> top5 = new ArrayList<>(); List<CalendarEvent> top5 = new ArrayList<>();
for(int i=0; i<Math.min(deviceEvents.size(), 5); i++) top5.add(deviceEvents.get(i)); for(int i=0; i<Math.min(deviceEvents.size(), 5); i++) top5.add(deviceEvents.get(i));
@ -173,7 +165,6 @@ public class HomeFragment extends Fragment {
private void fetchNewsFromWordpress(RecyclerView recyclerView) { private void fetchNewsFromWordpress(RecyclerView recyclerView) {
WordPressApiService apiService = RetrofitClient.getApiService(); WordPressApiService apiService = RetrofitClient.getApiService();
// Bruker getPosts som henter 5-10 innlegg med ?_embed
apiService.getPosts().enqueue(new Callback<List<WpPost>>() { apiService.getPosts().enqueue(new Callback<List<WpPost>>() {
@Override @Override
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) { public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
@ -181,8 +172,6 @@ public class HomeFragment extends Fragment {
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
List<WpPost> wpPosts = response.body(); List<WpPost> wpPosts = response.body();
// Datoformatering
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()); SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
rawFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); rawFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault()); SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
@ -192,15 +181,12 @@ public class HomeFragment extends Fragment {
try { try {
Date date = rawFormat.parse(post.date); Date date = rawFormat.parse(post.date);
post.date = targetFormat.format(date); post.date = targetFormat.format(date);
// Setter pen dato
} catch (Exception e) {} } catch (Exception e) {}
} }
// Sett adapter med Click Listener
NewsAdapter adapter = new NewsAdapter(wpPosts, post -> { NewsAdapter adapter = new NewsAdapter(wpPosts, post -> {
// Naviger til detaljvisning og send med post-objektet
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putSerializable("post_data", post); // WpPost er Serializable bundle.putSerializable("post_data", post);
Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsDetail, bundle); Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsDetail, bundle);
}); });
recyclerView.setAdapter(adapter); recyclerView.setAdapter(adapter);
@ -210,17 +196,16 @@ public class HomeFragment extends Fragment {
@Override @Override
public void onFailure(Call<List<WpPost>> call, Throwable t) { public void onFailure(Call<List<WpPost>> call, Throwable t) {
if (getContext() == null) return; if (getContext() == null) return;
// Ved feil, sett tom liste (eller vis feilmelding)
recyclerView.setAdapter(new NewsAdapter(new ArrayList<>(), null)); recyclerView.setAdapter(new NewsAdapter(new ArrayList<>(), null));
} }
}); });
} }
private void startNotificationWorker() { private void startNotificationWorker() {
// Kjører en jobb hvert 15. minutt for å sjekke om det er nye møter i HMS-kalenderen
PeriodicWorkRequest notifRequest = PeriodicWorkRequest notifRequest =
new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES) new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES)
.build(); .build();
WorkManager.getInstance(requireContext()).enqueue(notifRequest); WorkManager.getInstance(requireContext()).enqueue(notifRequest);
} }
} }

View file

@ -17,7 +17,6 @@ import java.util.Locale;
import retrofit2.Response; import retrofit2.Response;
public class NotificationWorker extends Worker { public class NotificationWorker extends Worker {
private static final String TAG = "KBS_DEBUG"; private static final String TAG = "KBS_DEBUG";
public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
@ -27,18 +26,22 @@ public class NotificationWorker extends Worker {
@NonNull @NonNull
@Override @Override
public Result doWork() { public Result doWork() {
Log.d(TAG, "NotificationWorker: Starter sjekk av kalender..."); Log.d(TAG, "NotificationWorker: Starter sjekk av kalender via WordPress Proxy...");
try { try {
String url = CalendarManager.getGoogleCalendarUrl(); Response<List<CalendarEvent>> response = RetrofitClient.getApiService().getCalendarEvents().execute();
Response<GoogleCalendarModels.Response> response = RetrofitClient.getApiService().getDirectGoogleEvents(url).execute();
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
List<CalendarEvent> events = CalendarManager.convertGoogleResponse(response.body()); List<CalendarEvent> events = response.body();
scheduleAlarms(events); scheduleAlarms(events);
return Result.success(); return Result.success();
} else { } else {
Log.e(TAG, "NotificationWorker: API-kall feilet. Kode: " + response.code()); int code = response.code();
Log.e(TAG, "NotificationWorker: API-kall mot WP feilet. Kode: " + code);
// Stopp retry ved klientfeil (4xx) inkludert 429
if (code >= 400 && code < 500) {
return Result.failure();
}
return Result.retry(); return Result.retry();
} }
} catch (IOException e) { } catch (IOException e) {
@ -53,54 +56,73 @@ public class NotificationWorker extends Worker {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (!alarmManager.canScheduleExactAlarms()) { if (!alarmManager.canScheduleExactAlarms()) {
Log.e(TAG, "NotificationWorker: MANGLER fortsatt tillatelse!"); Log.e(TAG, "NotificationWorker: MANGLER tillatelse for nøyaktige alarmer!");
return; return;
} }
} }
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()); SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
// Tillater alarmer som skulle gått for inntil 30 minutter siden (Catch-up)
long catchUpWindow = now - (30 * 60 * 1000L);
// Setter ikke alarmer lenger frem enn 24 timer
long futureWindow = now + (24 * 60 * 60 * 1000L);
int countSet = 0; int countSet = 0;
for (CalendarEvent event : events) { for (CalendarEvent event : events) {
try { try {
if (event.getRawDate().length() == 10) continue; String title = event.getTitle();
// Ignorer heldagshendelser (datoformat uten klokkeslett)
if (event.getRawDate() == null || event.getRawDate().length() == 10) continue;
Date eventDate = null; Date eventDate = null;
if (event.getRawDate().contains("T")) { if (event.getRawDate().contains("T")) {
String raw = event.getRawDate(); String raw = event.getRawDate();
// Kutter tidssone for å parse som lokal tid "face value"
if (raw.length() > 19) raw = raw.substring(0, 19); if (raw.length() > 19) raw = raw.substring(0, 19);
eventDate = isoFormat.parse(raw); eventDate = isoFormat.parse(raw);
} }
if (eventDate == null) continue; if (eventDate == null) continue;
long triggerTime = eventDate.getTime() - (event.getReminderMinutes() * 60 * 1000L); int minutesBefore = event.getReminderMinutes();
long triggerTime = eventDate.getTime() - (minutesBefore * 60 * 1000L);
// --- DETALJERT LOGGING FOR Å FEILSØKE --- // --- DIAGNOSE: Logg alle "Test"-events for å se hva PHP faktisk leverer ---
if (event.getTitle().toLowerCase().contains("test")) { if (title.toLowerCase().contains("test")) {
Log.d(TAG, "SJEKKER TEST-EVENT:"); Log.d(TAG, "--------------------------------------------------");
Log.d(TAG, " Start: " + eventDate); Log.d(TAG, "DIAGNOSE EVENT: " + title);
Log.d(TAG, " Varsling valgt: " + event.getReminderMinutes() + " min før"); Log.d(TAG, " Starttid: " + eventDate);
Log.d(TAG, " Alarmtid: " + new Date(triggerTime)); Log.d(TAG, " PHP sier reminderMinutes: " + minutesBefore);
Log.d(TAG, " Nå: " + new Date(now));
if (triggerTime > now) { if (minutesBefore <= 0) {
Log.d(TAG, " Status: I FREMTIDEN (Alarm skal settes)"); Log.d(TAG, " HANDLING: Skippes (Ingen varsling)");
} else { } else {
Log.d(TAG, " Status: I FORTIDEN (Hoppes over)"); Log.d(TAG, " Ønsket alarmtid: " + new Date(triggerTime));
Log.d(TAG, " Nå: " + new Date(now));
} }
} }
// ---------------------------------------- // ------------------------------------------------------------------------
if (triggerTime > now && triggerTime < (now + 24 * 60 * 60 * 1000L)) { if (minutesBefore <= 0) continue;
String uniqueIdString = event.getTitle() + event.getRawDate(); if (triggerTime > catchUpWindow && triggerTime < futureWindow) {
int alarmId = uniqueIdString.hashCode();
// CATCH-UP: Hvis tiden har passert, fyr av .
if (triggerTime < now) {
Log.i(TAG, " -> Alarmtid passert (" + new Date(triggerTime) + "). Kjører Catch-up NÅ.");
triggerTime = now + 1000;
}
int alarmId = (title + event.getRawDate()).hashCode();
Intent intent = new Intent(context, AlarmReceiver.class); Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("TITLE", event.getTitle()); intent.putExtra("TITLE", title);
intent.putExtra("MESSAGE", "Starter kl " + event.getTime()); String timeStr = new SimpleDateFormat("HH:mm", Locale.getDefault()).format(eventDate);
intent.putExtra("MESSAGE", "Starter kl " + timeStr);
intent.putExtra("ID", alarmId); intent.putExtra("ID", alarmId);
PendingIntent pendingIntent = PendingIntent.getBroadcast( PendingIntent pendingIntent = PendingIntent.getBroadcast(
@ -116,7 +138,10 @@ public class NotificationWorker extends Worker {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent); alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
} }
Log.i(TAG, ">>> ALARM SATT: " + event.getTitle()); if (title.toLowerCase().contains("test")) {
Log.d(TAG, " RESULTAT: ALARM SATT OK");
Log.d(TAG, "--------------------------------------------------");
}
countSet++; countSet++;
} }
@ -126,7 +151,7 @@ public class NotificationWorker extends Worker {
} }
if (countSet == 0) { if (countSet == 0) {
Log.d(TAG, "Ingen nye alarmer satt (ingen hendelser innenfor neste 24t)."); Log.d(TAG, "Ingen nye alarmer satt i denne runden.");
} }
} }
} }

View file

@ -1,7 +1,7 @@
package com.kbs.kbsintranett; package com.kbs.kbsintranett;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; // NY IMPORT import com.google.gson.JsonObject;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import okhttp3.MultipartBody; import okhttp3.MultipartBody;
@ -15,7 +15,6 @@ import retrofit2.http.Multipart;
import retrofit2.http.Part; import retrofit2.http.Part;
import retrofit2.http.PartMap; import retrofit2.http.PartMap;
import retrofit2.http.Query; import retrofit2.http.Query;
import retrofit2.http.Url; // NY IMPORT
public interface WordPressApiService { public interface WordPressApiService {
@GET("wp-json/wp/v2/posts?per_page=10&_embed") @GET("wp-json/wp/v2/posts?per_page=10&_embed")
@ -41,14 +40,11 @@ public interface WordPressApiService {
@Part List<MultipartBody.Part> files @Part List<MultipartBody.Part> files
); );
// ENDRET: Denne brukes ikke lenger for kalender, men beholdes for bakoverkompatibilitet // BRUKES : Henter kalenderhendelser via WordPress proxy.
// Dette sikrer at vi får med reminder_minutes fra serveren.
@GET("wp-json/kbs/v1/calendar/events") @GET("wp-json/kbs/v1/calendar/events")
Call<List<CalendarEvent>> getCalendarEvents(); Call<List<CalendarEvent>> getCalendarEvents();
// NY: Direkte kall mot Google (bruker @Url for å override base URL)
@GET
Call<GoogleCalendarModels.Response> getDirectGoogleEvents(@Url String fullUrl);
@GET("wp-json/gf/v2/entries") @GET("wp-json/gf/v2/entries")
Call<GravityEntryResponse> getEntries( Call<GravityEntryResponse> getEntries(
@Query("form_ids") int formId, @Query("form_ids") int formId,
@ -68,7 +64,7 @@ public interface WordPressApiService {
@GET("wp-json/kbs/v1/handbook/{id}") @GET("wp-json/kbs/v1/handbook/{id}")
Call<HandbookPage> getHandbookPage(@Path("id") int id); Call<HandbookPage> getHandbookPage(@Path("id") int id);
// NY: Slå opp ID fra URL
@GET("wp-json/kbs/v1/lookup-id") @GET("wp-json/kbs/v1/lookup-id")
Call<JsonObject> lookupPageId(@Query("url") String url); Call<JsonObject> lookupPageId(@Query("url") String url);
} }