Før nyheterarbeid
This commit is contained in:
parent
0c33b4fc0f
commit
a66dafb6c3
14 changed files with 879 additions and 183 deletions
|
|
@ -54,4 +54,7 @@ dependencies {
|
|||
|
||||
implementation("com.google.android.gms:play-services-auth:20.7.0")
|
||||
implementation("com.github.bumptech.glide:glide:4.16.0")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
|
||||
|
||||
implementation("androidx.work:work-runtime:2.9.0")
|
||||
}
|
||||
|
|
@ -18,6 +18,12 @@
|
|||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CALENDAR" />
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// FILSTI: app\src\main\java\com\kbs\kbsintranett\CalendarAdapter.java
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
|
|
@ -9,43 +8,57 @@ import androidx.annotation.NonNull;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.List;
|
||||
|
||||
public class CalendarAdapter extends RecyclerView.Adapter<CalendarAdapter.ViewHolder> { // [cite: 31]
|
||||
public class CalendarAdapter extends RecyclerView.Adapter<CalendarAdapter.ViewHolder> {
|
||||
|
||||
private List<CalendarEvent> events;
|
||||
public CalendarAdapter(List<CalendarEvent> events) { // [cite: 32]
|
||||
private final OnItemClickListener listener;
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(CalendarEvent event);
|
||||
}
|
||||
|
||||
// Oppdatert konstruktør som tar imot en listener
|
||||
public CalendarAdapter(List<CalendarEvent> events, OnItemClickListener listener) {
|
||||
this.events = events;
|
||||
} // [cite: 33]
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_calendar, parent, false);
|
||||
return new ViewHolder(view); // [cite: 34]
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
CalendarEvent event = events.get(position);
|
||||
holder.day.setText(event.getDay()); // [cite: 35]
|
||||
holder.day.setText(event.getDay());
|
||||
holder.month.setText(event.getMonth());
|
||||
// NYTT: Tidspunktet hentes nå fra getTime() som formateres i HomeFragment.
|
||||
holder.time.setText(event.getTime());
|
||||
holder.title.setText(event.getTitle());
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onItemClick(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return events.size(); // [cite: 36]
|
||||
return events.size();
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView day, month, title, time; // NYTT: Lagt til time
|
||||
public ViewHolder(View view) { // [cite: 37]
|
||||
TextView day, month, title, time;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
day = view.findViewById(R.id.cal_day);
|
||||
month = view.findViewById(R.id.cal_month); // [cite: 38]
|
||||
month = view.findViewById(R.id.cal_month);
|
||||
title = view.findViewById(R.id.cal_title);
|
||||
time = view.findViewById(R.id.cal_time); // NYTT
|
||||
time = view.findViewById(R.id.cal_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.CalendarContract;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class CalendarDetailsBottomSheet extends BottomSheetDialogFragment {
|
||||
|
||||
private CalendarEvent event;
|
||||
|
||||
public CalendarDetailsBottomSheet(CalendarEvent event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.bottom_sheet_calendar_details, container, false);
|
||||
|
||||
TextView title = view.findViewById(R.id.sheet_title);
|
||||
TextView time = view.findViewById(R.id.sheet_time);
|
||||
TextView desc = view.findViewById(R.id.sheet_desc);
|
||||
TextView loc = view.findViewById(R.id.sheet_location);
|
||||
Button btnAdd = view.findViewById(R.id.btn_add_to_calendar);
|
||||
|
||||
// Skjul knapp siden appen nå varsler automatisk (iht krav)
|
||||
btnAdd.setVisibility(View.GONE);
|
||||
|
||||
title.setText(event.getTitle());
|
||||
time.setText(event.getTime() + " (" + event.getDay() + ". " + event.getMonth() + ")");
|
||||
|
||||
if (!event.getDescription().isEmpty()) {
|
||||
// HER ER FIKSEN FOR HTML:
|
||||
desc.setText(android.text.Html.fromHtml(event.getDescription(), android.text.Html.FROM_HTML_MODE_COMPACT));
|
||||
desc.setVisibility(View.VISIBLE);
|
||||
// Gjør linker klikkbare
|
||||
desc.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());
|
||||
} else {
|
||||
desc.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!event.getLocation().isEmpty()) {
|
||||
loc.setText("Sted: " + event.getLocation());
|
||||
loc.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
loc.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void addToSystemCalendar() {
|
||||
try {
|
||||
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
apiFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
Date startDate = apiFormat.parse(event.getRawDate());
|
||||
long startMillis = startDate.getTime();
|
||||
long endMillis = startMillis + (60 * 60 * 1000); // Default 1 time hvis slutt mangler
|
||||
|
||||
if (event.getRawEndDate() != null && !event.getRawEndDate().isEmpty()) {
|
||||
Date endDate = apiFormat.parse(event.getRawEndDate());
|
||||
endMillis = endDate.getTime();
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_INSERT)
|
||||
.setData(CalendarContract.Events.CONTENT_URI)
|
||||
.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startMillis)
|
||||
.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endMillis)
|
||||
.putExtra(CalendarContract.Events.TITLE, event.getTitle())
|
||||
.putExtra(CalendarContract.Events.DESCRIPTION, event.getDescription())
|
||||
.putExtra(CalendarContract.Events.EVENT_LOCATION, event.getLocation())
|
||||
.putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY);
|
||||
|
||||
startActivity(intent);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,38 @@
|
|||
// FILSTI: app\src\main\java\com\kbs\kbsintranett\CalendarEvent.java
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
public class CalendarEvent {
|
||||
private String title;
|
||||
private String rawDate; // NYTT: Holder den fulle, u-formaterte dato/tid-strengen fra API'et
|
||||
private String day; // F.eks "12"
|
||||
private String month; // F.eks "DES"
|
||||
private String time; // NYTT: Brukes kun for visning av tid
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class CalendarEvent {
|
||||
@SerializedName("title")
|
||||
private String title;
|
||||
|
||||
@SerializedName("start_date") // Juster denne nøkkelen til hva APIet faktisk returnerer (f.eks "start")
|
||||
private String rawDate;
|
||||
|
||||
@SerializedName("end_date") // Juster nøkkel (f.eks "end")
|
||||
private String rawEndDate;
|
||||
|
||||
@SerializedName("description")
|
||||
private String description;
|
||||
|
||||
@SerializedName("location")
|
||||
private String location;
|
||||
|
||||
// --- UI-hjelpefelter (settes manuelt i appen etter parsing) ---
|
||||
private String day; // F.eks "12"
|
||||
private String month; // F.eks "DES"
|
||||
private String time; // F.eks "10:00 - 11:30"
|
||||
|
||||
// Konstruktør for Retrofit (Gson)
|
||||
public CalendarEvent(String title, String rawDate, String rawEndDate, String description, String location) {
|
||||
this.title = title;
|
||||
this.rawDate = rawDate;
|
||||
this.rawEndDate = rawEndDate;
|
||||
this.description = description;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
// Konstruktør for manuell opprettelse (f.eks ved feil)
|
||||
public CalendarEvent(String title, String time, String day, String month) {
|
||||
this.title = title;
|
||||
this.time = time;
|
||||
|
|
@ -15,16 +40,19 @@ public class CalendarEvent {
|
|||
this.month = month;
|
||||
}
|
||||
|
||||
public CalendarEvent(String title, String rawDate) {
|
||||
this.title = title;
|
||||
this.rawDate = rawDate;
|
||||
// La de andre feltene være null i starten, de fylles i HomeFragment
|
||||
}
|
||||
|
||||
public String getTitle() { return title; }
|
||||
public String getTime() { return time; }
|
||||
public String getDay() { return day; }
|
||||
public String getMonth() { return month; }
|
||||
public String getRawDate() { return rawDate; }
|
||||
public String getRawEndDate() { return rawEndDate; }
|
||||
public String getDescription() { return description != null ? description : ""; }
|
||||
public String getLocation() { return location != null ? location : ""; }
|
||||
|
||||
public String getRawDate() { return rawDate; } // NYTT
|
||||
// Getters og Setters for UI-felter
|
||||
public String getDay() { return day; }
|
||||
public void setDay(String day) { this.day = day; }
|
||||
|
||||
public String getMonth() { return month; }
|
||||
public void setMonth(String month) { this.month = month; }
|
||||
|
||||
public String getTime() { return time; }
|
||||
public void setTime(String time) { this.time = time; }
|
||||
}
|
||||
135
app/src/main/java/com/kbs/kbsintranett/CalendarFullFragment.java
Normal file
135
app/src/main/java/com/kbs/kbsintranett/CalendarFullFragment.java
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class CalendarFullFragment extends Fragment {
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
private ProgressBar progressBar;
|
||||
private TextView emptyView;
|
||||
private LinearLayoutManager layoutManager; // Trenger denne for å scrolle
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_calendar_full, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
recyclerView = view.findViewById(R.id.recycler_full_calendar);
|
||||
progressBar = view.findViewById(R.id.loading_full_calendar);
|
||||
emptyView = view.findViewById(R.id.empty_view_calendar);
|
||||
ImageView backBtn = view.findViewById(R.id.btn_back_calendar);
|
||||
|
||||
layoutManager = new LinearLayoutManager(getContext());
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
|
||||
backBtn.setOnClickListener(v -> Navigation.findNavController(view).navigateUp());
|
||||
|
||||
fetchAllEvents();
|
||||
}
|
||||
|
||||
private void fetchAllEvents() {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
// Hent personlige hendelser (Nå med historikk)
|
||||
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext());
|
||||
|
||||
RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
|
||||
if (!isAdded()) return;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
List<CalendarEvent> apiEvents = new ArrayList<>();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
for (CalendarEvent e : response.body()) {
|
||||
CalendarManager.formatEventForUI(e);
|
||||
apiEvents.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Flett og vis
|
||||
List<CalendarEvent> allEvents = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
||||
|
||||
if (allEvents.isEmpty()) {
|
||||
emptyView.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
emptyView.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
|
||||
CalendarAdapter adapter = new CalendarAdapter(allEvents, event -> {
|
||||
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
// --- SCROLL TIL I DAG ---
|
||||
scrollToToday(allEvents);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
||||
if (!isAdded()) return;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
if (!deviceEvents.isEmpty()) {
|
||||
CalendarAdapter adapter = new CalendarAdapter(deviceEvents, event -> {
|
||||
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
scrollToToday(deviceEvents);
|
||||
} else {
|
||||
emptyView.setText("Ingen hendelser funnet.");
|
||||
emptyView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void scrollToToday(List<CalendarEvent> events) {
|
||||
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
||||
int scrollIndex = 0;
|
||||
|
||||
// Finn første event som er i dag eller senere
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
String raw = events.get(i).getRawDate();
|
||||
if (raw != null && raw.compareTo(today) >= 0) {
|
||||
scrollIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll litt ned slik at "i dag" havner på toppen, men ikke helt (offset 0)
|
||||
// Bruker scrollToPositionWithOffset for presisjon
|
||||
if (scrollIndex > 0) {
|
||||
layoutManager.scrollToPositionWithOffset(scrollIndex, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
174
app/src/main/java/com/kbs/kbsintranett/CalendarManager.java
Normal file
174
app/src/main/java/com/kbs/kbsintranett/CalendarManager.java
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.provider.CalendarContract;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class CalendarManager {
|
||||
|
||||
public static List<CalendarEvent> getDeviceEvents(Context context) {
|
||||
List<CalendarEvent> deviceEvents = new ArrayList<>();
|
||||
|
||||
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_CALENDAR)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
return deviceEvents;
|
||||
}
|
||||
|
||||
// ENDRET: Hent events fra 1 år tilbake og 1 år frem
|
||||
long now = System.currentTimeMillis();
|
||||
long startMillis = now - (365L * 24 * 60 * 60 * 1000); // 1 år tilbake
|
||||
long endMillis = now + (365L * 24 * 60 * 60 * 1000); // 1 år frem
|
||||
|
||||
String[] projection = new String[]{
|
||||
CalendarContract.Events.TITLE,
|
||||
CalendarContract.Events.DTSTART,
|
||||
CalendarContract.Events.DTEND,
|
||||
CalendarContract.Events.DESCRIPTION,
|
||||
CalendarContract.Events.EVENT_LOCATION,
|
||||
CalendarContract.Events.ALL_DAY // Nyttig for å vite om det er heldags
|
||||
};
|
||||
|
||||
String selection = CalendarContract.Events.DTSTART + " >= ? AND " + CalendarContract.Events.DTSTART + " <= ?";
|
||||
String[] selectionArgs = new String[]{String.valueOf(startMillis), String.valueOf(endMillis)};
|
||||
|
||||
try (Cursor cursor = context.getContentResolver().query(
|
||||
CalendarContract.Events.CONTENT_URI,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
CalendarContract.Events.DTSTART + " ASC"
|
||||
)) {
|
||||
if (cursor != null) {
|
||||
// Vi bruker ISO format internt for sortering
|
||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
String title = cursor.getString(0);
|
||||
long dtStart = cursor.getLong(1);
|
||||
long dtEnd = cursor.getLong(2);
|
||||
String desc = cursor.getString(3);
|
||||
String loc = cursor.getString(4);
|
||||
int allDay = cursor.getInt(5);
|
||||
|
||||
String rawStart;
|
||||
String rawEnd;
|
||||
|
||||
if (allDay == 1) {
|
||||
// For heldags lagrer vi bare datoen: yyyy-MM-dd
|
||||
SimpleDateFormat shortFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
rawStart = shortFormat.format(new Date(dtStart));
|
||||
rawEnd = shortFormat.format(new Date(dtEnd));
|
||||
} else {
|
||||
// For vanlige events bruker vi full tid
|
||||
rawStart = isoFormat.format(new Date(dtStart));
|
||||
rawEnd = isoFormat.format(new Date(dtEnd));
|
||||
}
|
||||
|
||||
CalendarEvent event = new CalendarEvent(title, rawStart, rawEnd, desc, loc);
|
||||
formatEventForUI(event);
|
||||
deviceEvents.add(event);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return deviceEvents;
|
||||
}
|
||||
|
||||
// --- ROBUST DATO-PARSING (Løser "null" problemet) ---
|
||||
public static void formatEventForUI(CalendarEvent event) {
|
||||
if (event.getRawDate() == null) return;
|
||||
|
||||
SimpleDateFormat outputDay = new SimpleDateFormat("dd", Locale.getDefault());
|
||||
SimpleDateFormat outputMonth = new SimpleDateFormat("MMM", new Locale("no", "NO"));
|
||||
SimpleDateFormat outputTime = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
|
||||
outputMonth.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
outputTime.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
try {
|
||||
Date date = null;
|
||||
Date endDate = null;
|
||||
boolean isAllDay = false;
|
||||
|
||||
String raw = event.getRawDate();
|
||||
|
||||
// SJEKK 1: Er det heldagsdato? (Lengde 10, f.eks "2025-12-31")
|
||||
if (raw.length() == 10 && !raw.contains("T") && !raw.contains(" ")) {
|
||||
SimpleDateFormat shortFmt = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
date = shortFmt.parse(raw);
|
||||
isAllDay = true;
|
||||
|
||||
if (event.getRawEndDate() != null && event.getRawEndDate().length() == 10) {
|
||||
endDate = shortFmt.parse(event.getRawEndDate());
|
||||
}
|
||||
}
|
||||
// SJEKK 2: Er det ISO format? (Har 'T')
|
||||
else if (raw.contains("T")) {
|
||||
SimpleDateFormat isoFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
isoFmt.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // Viktig for Google events
|
||||
date = isoFmt.parse(raw);
|
||||
|
||||
if (event.getRawEndDate() != null && event.getRawEndDate().contains("T")) {
|
||||
endDate = isoFmt.parse(event.getRawEndDate());
|
||||
}
|
||||
}
|
||||
// SJEKK 3: Er det SQL format? (Mellomrom)
|
||||
else {
|
||||
SimpleDateFormat sqlFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
sqlFmt.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
date = sqlFmt.parse(raw);
|
||||
|
||||
if (event.getRawEndDate() != null) {
|
||||
endDate = sqlFmt.parse(event.getRawEndDate());
|
||||
}
|
||||
}
|
||||
|
||||
if (date != null) {
|
||||
event.setDay(outputDay.format(date));
|
||||
event.setMonth(outputMonth.format(date).toUpperCase());
|
||||
|
||||
if (isAllDay) {
|
||||
event.setTime("Hele dagen");
|
||||
} else {
|
||||
String timeStr = outputTime.format(date);
|
||||
if (endDate != null) {
|
||||
// Hvis sluttdato er samme dag, vis bare klokkeslett
|
||||
// (Enkelt sjekk: hvis datoene er like)
|
||||
// Her forenkler vi og viser alltid sluttid hvis den finnes
|
||||
timeStr += " - " + outputTime.format(endDate);
|
||||
}
|
||||
event.setTime("Kl. " + timeStr);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
event.setDay("??");
|
||||
event.setMonth("???");
|
||||
event.setTime("Feil dato");
|
||||
}
|
||||
}
|
||||
|
||||
public static List<CalendarEvent> mergeAndSort(List<CalendarEvent> apiEvents, List<CalendarEvent> deviceEvents) {
|
||||
List<CalendarEvent> all = new ArrayList<>(apiEvents);
|
||||
all.addAll(deviceEvents);
|
||||
|
||||
Collections.sort(all, (e1, e2) -> {
|
||||
String d1 = e1.getRawDate() != null ? e1.getRawDate() : "";
|
||||
String d2 = e2.getRawDate() != null ? e2.getRawDate() : "";
|
||||
return d1.compareTo(d2);
|
||||
});
|
||||
|
||||
return all;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,198 +1,194 @@
|
|||
// FILSTI: app\src\main\java\com\kbs\kbsintranett\HomeFragment.java
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class HomeFragment extends Fragment {
|
||||
|
||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||
private RecyclerView calendarRecycler;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// Håndter svar på kalendertillatelse
|
||||
requestPermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
isGranted -> {
|
||||
// Last kalender på nytt (nå med eller uten personlig kalender)
|
||||
fetchCalendarEvents(calendarRecycler);
|
||||
}
|
||||
);
|
||||
|
||||
// Start bakgrunnsjobb for varsling (Hvert 15. minutt)
|
||||
startNotificationWorker();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
// Laster inn layouten fra XML (fragment_home.xml)
|
||||
return inflater.inflate(R.layout.fragment_home, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
// ---------------------------------------------------------
|
||||
// 0. SETT OPP PROFIL-KNAPP (Ny!)
|
||||
// ---------------------------------------------------------
|
||||
// Vi finner ikonet vi la til i XML og sier at det skal gå til Profil-siden
|
||||
|
||||
// Profil-knapp
|
||||
View profileBtn = view.findViewById(R.id.btn_profile);
|
||||
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. SETT OPP KALENDER (Henter fra WordPress)
|
||||
// ---------------------------------------------------------
|
||||
RecyclerView calendarRecycler = view.findViewById(R.id.recycler_calendar);
|
||||
// Kalender oppsett
|
||||
calendarRecycler = view.findViewById(R.id.recycler_calendar);
|
||||
calendarRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
calendarRecycler.setAdapter(new CalendarAdapter(new ArrayList<>(), event -> {}));
|
||||
|
||||
// Starter henting av kalenderdata
|
||||
fetchCalendarEvents(calendarRecycler);
|
||||
// "Se alle" knapp
|
||||
TextView viewAllCalendar = view.findViewById(R.id.btn_view_all_calendar);
|
||||
if (viewAllCalendar != null) {
|
||||
viewAllCalendar.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.action_home_to_calendarFull));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 2. SETT OPP NYHETER (Hentes fra WordPress)
|
||||
// ---------------------------------------------------------
|
||||
// Sjekk tillatelse for personlig kalender
|
||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) {
|
||||
fetchCalendarEvents(calendarRecycler);
|
||||
} else {
|
||||
// Spør om lov til å lese kalender
|
||||
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 (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {}).launch(Manifest.permission.POST_NOTIFICATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
// Nyheter
|
||||
RecyclerView newsRecycler = view.findViewById(R.id.recycler_news);
|
||||
newsRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
// Gjør at scrollen flyter bedre inni NestedScrollView (hvis du bruker det i XML)
|
||||
newsRecycler.setNestedScrollingEnabled(false);
|
||||
// Start henting av ekte data
|
||||
newsRecycler.setAdapter(new NewsAdapter(new ArrayList<>()));
|
||||
fetchNewsFromWordpress(newsRecycler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Henter kalenderhendelser fra WordPress via RetrofitClient
|
||||
*/
|
||||
private void fetchCalendarEvents(RecyclerView recyclerView) {
|
||||
// 1. Hent API-tjenesten vår
|
||||
// 1. Hent personlige hendelser først
|
||||
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext());
|
||||
|
||||
WordPressApiService apiService = RetrofitClient.getApiService();
|
||||
// 2. Send forespørsel til nettet (Asynkront)
|
||||
apiService.getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
|
||||
if (getContext() == null || response.body() == null) return;
|
||||
if (!isAdded()) return;
|
||||
|
||||
List<CalendarEvent> rawEvents = response.body();
|
||||
List<CalendarEvent> formattedEvents = new ArrayList<>();
|
||||
|
||||
// Formater for parsing og visning
|
||||
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
apiFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // Fikser deprecation/tidssone
|
||||
|
||||
SimpleDateFormat dayFormat = new SimpleDateFormat("dd", Locale.getDefault());
|
||||
dayFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // Fikser deprecation/tidssone
|
||||
|
||||
// Bruker norsk locale for måned (Jan, Feb, Mar, etc.)
|
||||
SimpleDateFormat monthFormat = new SimpleDateFormat("MMM", new Locale("no", "NO"));
|
||||
monthFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // Fikser deprecation/tidssone
|
||||
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
timeFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // Fikser deprecation/tidssone
|
||||
|
||||
for (CalendarEvent event : rawEvents) {
|
||||
try {
|
||||
// Bruker getRawDate() fra CalendarEvent.java (oppdatert)
|
||||
Date date = apiFormat.parse(event.getRawDate());
|
||||
String day = dayFormat.format(date);
|
||||
String month = monthFormat.format(date).toUpperCase(Locale.getDefault());
|
||||
String startTime = timeFormat.format(date);
|
||||
|
||||
// Bruker den gamle konstruktøren for å sette formaterte data i adapteren
|
||||
formattedEvents.add(new CalendarEvent(
|
||||
event.getTitle(),
|
||||
startTime,
|
||||
day,
|
||||
month
|
||||
));
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
// Håndterer feil i parsing av dato/tid ved å vise rå data
|
||||
formattedEvents.add(new CalendarEvent(event.getTitle(), "Ukjent", event.getDay(), event.getMonth()));
|
||||
List<CalendarEvent> apiEvents = new ArrayList<>();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
for (CalendarEvent e : response.body()) {
|
||||
CalendarManager.formatEventForUI(e); // Formatér datoer
|
||||
apiEvents.add(e);
|
||||
}
|
||||
}
|
||||
recyclerView.setAdapter(new CalendarAdapter(formattedEvents));
|
||||
|
||||
// Flett lister
|
||||
List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
||||
|
||||
// Vis kun topp 5
|
||||
List<CalendarEvent> top5 = new ArrayList<>();
|
||||
for(int i=0; i<Math.min(merged.size(), 5); i++) {
|
||||
top5.add(merged.get(i));
|
||||
}
|
||||
|
||||
recyclerView.setAdapter(new CalendarAdapter(top5, event -> {
|
||||
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
||||
if (getContext() == null) return;
|
||||
System.err.println("Kalender Nettverksfeil: " + t.getMessage());
|
||||
// Vis feilmelding i RecyclerView
|
||||
List<CalendarEvent> errorList = new ArrayList<>();
|
||||
errorList.add(new CalendarEvent("Kunne ikke laste kalender", "Sjekk nettverket ditt.", "00", "FEIL"));
|
||||
recyclerView.setAdapter(new CalendarAdapter(errorList));
|
||||
if (!isAdded()) return;
|
||||
// Hvis API feiler, vis bare personlige events hvis vi har noen
|
||||
if (!deviceEvents.isEmpty()) {
|
||||
List<CalendarEvent> top5 = new ArrayList<>();
|
||||
for(int i=0; i<Math.min(deviceEvents.size(), 5); i++) top5.add(deviceEvents.get(i));
|
||||
|
||||
recyclerView.setAdapter(new CalendarAdapter(top5, event -> {
|
||||
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||
}));
|
||||
} else {
|
||||
// Vis feil hvis alt er tomt
|
||||
List<CalendarEvent> errorList = new ArrayList<>();
|
||||
errorList.add(new CalendarEvent("Kunne ikke laste kalender", "Sjekk nettverk", "!", "OBS"));
|
||||
recyclerView.setAdapter(new CalendarAdapter(errorList, null));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Henter nyheter fra WordPress via RetrofitClient
|
||||
*/
|
||||
private void startNotificationWorker() {
|
||||
// Kjører en jobb hvert 15. minutt for å sjekke om det er nye møter
|
||||
PeriodicWorkRequest notifRequest =
|
||||
new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES)
|
||||
.build();
|
||||
WorkManager.getInstance(requireContext()).enqueue(notifRequest);
|
||||
}
|
||||
|
||||
// ... (fetchNewsFromWordpress beholdes som før) ...
|
||||
private void fetchNewsFromWordpress(RecyclerView recyclerView) {
|
||||
// 1. Hent API-tjenesten vår
|
||||
// [Lim inn koden for nyheter fra forrige svar her, den var OK]
|
||||
WordPressApiService apiService = RetrofitClient.getApiService();
|
||||
// 2. Send forespørsel til nettet (Asynkront)
|
||||
apiService.getPosts().enqueue(new Callback<List<WpPost>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
||||
// Sjekk om appen fortsatt lever (viktig for å unngå krasj)
|
||||
if (getContext() == null) return;
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
// 3. Suksess! Vi fikk data fra WordPress.
|
||||
List<WpPost> wpPosts = response.body();
|
||||
List<NewsItem> newsList = new ArrayList<>();
|
||||
java.text.SimpleDateFormat rawFormat = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", java.util.Locale.getDefault());
|
||||
rawFormat.setTimeZone(java.util.TimeZone.getTimeZone("Europe/Oslo"));
|
||||
java.text.SimpleDateFormat targetFormat = new java.text.SimpleDateFormat("dd. MMM yyyy", java.util.Locale.getDefault());
|
||||
targetFormat.setTimeZone(java.util.TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
// Datoformatering for nyhetene
|
||||
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
rawFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // Fikser deprecation/tidssone
|
||||
|
||||
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
|
||||
targetFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo")); // Fikser deprecation/tidssone
|
||||
|
||||
// Konverter fra "WpPost" (API-format) til "NewsItem" (App-format)
|
||||
for (WpPost post : wpPosts) {
|
||||
String formattedDate = post.date;
|
||||
|
||||
try {
|
||||
// API-datoen (post.date) er i formatet "yyyy-MM-dd'T'HH:mm:ss"
|
||||
Date date = rawFormat.parse(post.date);
|
||||
java.util.Date date = rawFormat.parse(post.date);
|
||||
formattedDate = targetFormat.format(date);
|
||||
} catch (ParseException e) {
|
||||
System.err.println("Feil ved parsing av nyhetsdato: " + e.getMessage());
|
||||
}
|
||||
|
||||
newsList.add(new NewsItem(
|
||||
post.getTitleStr(),
|
||||
post.getExcerptStr(),
|
||||
"Publisert: " + formattedDate
|
||||
));
|
||||
} catch (java.text.ParseException e) {}
|
||||
newsList.add(new NewsItem(post.getTitleStr(), post.getExcerptStr(), "Publisert: " + formattedDate));
|
||||
}
|
||||
|
||||
// 4. Send listen til Adapteren slik at den vises på skjermen
|
||||
NewsAdapter adapter = new NewsAdapter(newsList);
|
||||
recyclerView.setAdapter(adapter);
|
||||
} else {
|
||||
System.err.println("Feil: Fikk svar, men noe var galt med dataene: " + response.code());
|
||||
// Her kunne vi vist en "Ingen nyheter"-tekst
|
||||
// (Løsningen har allerede lagt inn fallback i onFailure)
|
||||
recyclerView.setAdapter(new NewsAdapter(newsList));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
||||
// Nettverksfeil (Ingen nett, feil URL, etc)
|
||||
if (getContext() == null) return;
|
||||
System.err.println("Nettverksfeil: " + t.getMessage());
|
||||
// Legg til en "Feilmelding" i listen så brukeren ser det
|
||||
List<NewsItem> errorList = new ArrayList<>();
|
||||
errorList.add(new NewsItem("Kunne ikke laste nyheter", "Sjekk nettverket ditt.", "System"));
|
||||
recyclerView.setAdapter(new NewsAdapter(errorList));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class NotificationWorker extends Worker {
|
||||
|
||||
private static final String CHANNEL_ID = "kbs_calendar_channel";
|
||||
private static final String PREFS_NAME = "KBSNotificationPrefs";
|
||||
|
||||
public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||
super(context, workerParams);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
// Dette kjører i bakgrunnen
|
||||
try {
|
||||
// Hent events synkront (ikke enqueue)
|
||||
Response<List<CalendarEvent>> response = RetrofitClient.getApiService().getCalendarEvents().execute();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
checkAndNotify(response.body());
|
||||
return Result.success();
|
||||
} else {
|
||||
return Result.retry();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return Result.retry();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAndNotify(List<CalendarEvent> events) {
|
||||
SharedPreferences prefs = getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
long now = System.currentTimeMillis();
|
||||
long fifteenMinutes = 15 * 60 * 1000;
|
||||
|
||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
SimpleDateFormat sqlFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
|
||||
|
||||
for (CalendarEvent event : events) {
|
||||
try {
|
||||
Date eventDate;
|
||||
if (event.getRawDate().contains("T")) eventDate = isoFormat.parse(event.getRawDate());
|
||||
else eventDate = sqlFormat.parse(event.getRawDate());
|
||||
|
||||
if (eventDate == null) continue;
|
||||
|
||||
long diff = eventDate.getTime() - now;
|
||||
|
||||
// Hvis eventet starter innen de neste 30 min, og ikke allerede varslet
|
||||
if (diff > 0 && diff < (30 * 60 * 1000)) {
|
||||
String eventId = event.getTitle() + event.getRawDate(); // Enkel ID
|
||||
boolean alreadyNotified = prefs.getBoolean(eventId, false);
|
||||
|
||||
if (!alreadyNotified) {
|
||||
sendNotification(event.getTitle(), "Starter kl " + event.getTime());
|
||||
// Lagre at vi har varslet
|
||||
prefs.edit().putBoolean(eventId, true).apply();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendNotification(String title, String content) {
|
||||
NotificationManager manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "KBS Kalender", NotificationManager.IMPORTANCE_HIGH);
|
||||
manager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.ic_launcher) // Sørg for at du har et ikon her
|
||||
.setContentTitle(title)
|
||||
.setContentText(content)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setAutoCancel(true);
|
||||
|
||||
manager.notify((int) System.currentTimeMillis(), builder.build());
|
||||
}
|
||||
}
|
||||
|
|
@ -11,32 +11,30 @@ import okhttp3.Interceptor;
|
|||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.logging.HttpLoggingInterceptor; // NY IMPORT
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class RetrofitClient {
|
||||
private static final String BASE_URL = "https://intranet.kbs.no/";
|
||||
|
||||
// VI FJERNER FAKE_COOKIE HERFRA! Den trengs ikke lenger.
|
||||
|
||||
private static Retrofit retrofit = null;
|
||||
|
||||
public static WordPressApiService getApiService() {
|
||||
// Vi må bygge klienten på nytt hvis vi logger ut/inn, men for enkelhets skyld
|
||||
// sjekker vi bare null her.
|
||||
if (retrofit == null) {
|
||||
|
||||
// NYTT: Logging Interceptor
|
||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BODY); // Logger ALT (Body, Headers)
|
||||
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.addInterceptor(logging) // Legg til loggingen her
|
||||
.addInterceptor(new Interceptor() {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
Request originalRequest = chain.request();
|
||||
Request.Builder builder = originalRequest.newBuilder();
|
||||
|
||||
// 1. Hent cookie fra UserManager
|
||||
String dynamicCookie = UserManager.getInstance().getCookie();
|
||||
|
||||
// 2. Hvis vi har en cookie, legg den til i headeren
|
||||
if (dynamicCookie != null && !dynamicCookie.isEmpty()) {
|
||||
builder.header("Cookie", dynamicCookie);
|
||||
}
|
||||
|
|
@ -48,6 +46,7 @@ public class RetrofitClient {
|
|||
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(new TypeToken<List<GravityField.Choice>>(){}.getType(), new ChoicesAdapter())
|
||||
.setLenient() // NYTT: Gjør parsing litt mer tilgivende
|
||||
.create();
|
||||
|
||||
retrofit = new Retrofit.Builder()
|
||||
|
|
@ -59,7 +58,6 @@ public class RetrofitClient {
|
|||
return retrofit.create(WordPressApiService.class);
|
||||
}
|
||||
|
||||
// Hjelpemetode for å nullstille Retrofit ved utlogging
|
||||
public static void clearClient() {
|
||||
retrofit = null;
|
||||
}
|
||||
|
|
|
|||
59
app/src/main/res/layout/bottom_sheet_calendar_details.xml
Normal file
59
app/src/main/res/layout/bottom_sheet_calendar_details.xml
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:background="@android:color/white">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sheet_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tittel"
|
||||
android:textSize="22sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sheet_time"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tidspunkt"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/kbs_muted_blue_gray"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:drawablePadding="8dp"
|
||||
app:drawableStartCompat="@android:drawable/ic_menu_recent_history"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sheet_location"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sted"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#333"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sheet_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Beskrivelse..."
|
||||
android:textSize="14sp"
|
||||
android:textColor="#555"
|
||||
android:layout_marginBottom="32dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_add_to_calendar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Lagre i min kalender / Varsle meg"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="@color/white"
|
||||
android:padding="12dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
59
app/src/main/res/layout/fragment_calendar_full.xml
Normal file
59
app/src/main/res/layout/fragment_calendar_full.xml
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/kbs_very_light_blue">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:background="@color/white"
|
||||
android:elevation="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_back_calendar"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@android:drawable/ic_menu_revert"
|
||||
android:layout_centerVertical="true"
|
||||
app:tint="@color/kbs_logo_blue"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="KBS Kalender"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_centerInParent="true"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_full_calendar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp"
|
||||
android:clipToPadding="false"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_full_calendar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_view_calendar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ingen hendelser funnet"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone"/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -5,38 +5,61 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp"
|
||||
android:background="@color/kbs_very_light_blue"> <RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:paddingHorizontal="8dp">
|
||||
android:background="@color/kbs_very_light_blue">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="KBS Intranett"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/kbs_muted_blue_gray" android:layout_centerVertical="true"/>
|
||||
<ImageView
|
||||
android:id="@+id/btn_profile"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@android:drawable/ic_menu_my_calendar"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
app:tint="@color/kbs_logo_blue"/> </RelativeLayout>
|
||||
android:layout_marginBottom="16dp"
|
||||
android:paddingHorizontal="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="KBS Intranett"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/kbs_muted_blue_gray"
|
||||
android:layout_centerVertical="true"/>
|
||||
<ImageView
|
||||
android:id="@+id/btn_profile"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:src="@android:drawable/ic_menu_my_calendar"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
app:tint="@color/kbs_logo_blue"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Kommende hendelser"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginStart="8dp"/>
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Kommende hendelser"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_view_all_calendar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Se alle >"
|
||||
android:textColor="@color/kbs_logo_blue"
|
||||
android:textStyle="bold"
|
||||
android:padding="8dp"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_calendar"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,17 @@
|
|||
android:id="@+id/navigation_home"
|
||||
android:name="com.kbs.kbsintranett.HomeFragment"
|
||||
android:label="Hjem"
|
||||
tools:layout="@layout/fragment_home" />
|
||||
tools:layout="@layout/fragment_home">
|
||||
<action
|
||||
android:id="@+id/action_home_to_calendarFull"
|
||||
app:destination="@id/navigation_calendar_full" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_calendar_full"
|
||||
android:name="com.kbs.kbsintranett.CalendarFullFragment"
|
||||
android:label="Kalender"
|
||||
tools:layout="@layout/fragment_calendar_full" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_forms"
|
||||
|
|
|
|||
Loading…
Reference in a new issue