Før ny chat
This commit is contained in:
parent
a66dafb6c3
commit
b74c8715ef
21 changed files with 2854 additions and 412 deletions
|
|
@ -15,6 +15,38 @@ import java.util.TimeZone;
|
|||
|
||||
public class CalendarManager {
|
||||
|
||||
// NY HJELPEMETODE: Finner ID-ene til kalendere som tilhører @kbs.no
|
||||
private static List<String> getKbsCalendarIds(Context context) {
|
||||
List<String> ids = new ArrayList<>();
|
||||
|
||||
String[] projection = new String[] {
|
||||
CalendarContract.Calendars._ID,
|
||||
CalendarContract.Calendars.ACCOUNT_NAME
|
||||
};
|
||||
|
||||
// Vi ser etter kontoer som slutter på @kbs.no
|
||||
// (SQL: account_name LIKE '%@kbs.no')
|
||||
String selection = CalendarContract.Calendars.ACCOUNT_NAME + " LIKE ?";
|
||||
String[] selectionArgs = new String[] {"%@kbs.no"};
|
||||
|
||||
try (Cursor cursor = context.getContentResolver().query(
|
||||
CalendarContract.Calendars.CONTENT_URI,
|
||||
projection,
|
||||
selection,
|
||||
selectionArgs,
|
||||
null
|
||||
)) {
|
||||
if (cursor != null) {
|
||||
while (cursor.moveToNext()) {
|
||||
ids.add(cursor.getString(0)); // Legg til kalender-ID
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
public static List<CalendarEvent> getDeviceEvents(Context context) {
|
||||
List<CalendarEvent> deviceEvents = new ArrayList<>();
|
||||
|
||||
|
|
@ -23,10 +55,18 @@ public class CalendarManager {
|
|||
return deviceEvents;
|
||||
}
|
||||
|
||||
// ENDRET: Hent events fra 1 år tilbake og 1 år frem
|
||||
// 1. Finn først ID-ene til KBS-kalenderne
|
||||
List<String> kbsCalendarIds = getKbsCalendarIds(context);
|
||||
|
||||
// Hvis ingen kbs-kalendere finnes på telefonen, returner tom liste
|
||||
if (kbsCalendarIds.isEmpty()) {
|
||||
return deviceEvents;
|
||||
}
|
||||
|
||||
// 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
|
||||
long startMillis = now - (365L * 24 * 60 * 60 * 1000);
|
||||
long endMillis = now + (365L * 24 * 60 * 60 * 1000);
|
||||
|
||||
String[] projection = new String[]{
|
||||
CalendarContract.Events.TITLE,
|
||||
|
|
@ -34,21 +74,39 @@ public class CalendarManager {
|
|||
CalendarContract.Events.DTEND,
|
||||
CalendarContract.Events.DESCRIPTION,
|
||||
CalendarContract.Events.EVENT_LOCATION,
|
||||
CalendarContract.Events.ALL_DAY // Nyttig for å vite om det er heldags
|
||||
CalendarContract.Events.ALL_DAY
|
||||
};
|
||||
|
||||
String selection = CalendarContract.Events.DTSTART + " >= ? AND " + CalendarContract.Events.DTSTART + " <= ?";
|
||||
String[] selectionArgs = new String[]{String.valueOf(startMillis), String.valueOf(endMillis)};
|
||||
// 2. Bygg opp spørringen for å filtrere på disse ID-ene
|
||||
// Resultatet blir noe sånt som: "((calendar_id = ?) OR (calendar_id = ?)) AND dtstart >= ? AND dtstart <= ?"
|
||||
StringBuilder selection = new StringBuilder("(");
|
||||
List<String> selectionArgsList = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < kbsCalendarIds.size(); i++) {
|
||||
selection.append(CalendarContract.Events.CALENDAR_ID).append(" = ?");
|
||||
selectionArgsList.add(kbsCalendarIds.get(i));
|
||||
if (i < kbsCalendarIds.size() - 1) {
|
||||
selection.append(" OR ");
|
||||
}
|
||||
}
|
||||
selection.append(") AND ");
|
||||
|
||||
selection.append(CalendarContract.Events.DTSTART).append(" >= ? AND ");
|
||||
selection.append(CalendarContract.Events.DTSTART).append(" <= ?");
|
||||
|
||||
selectionArgsList.add(String.valueOf(startMillis));
|
||||
selectionArgsList.add(String.valueOf(endMillis));
|
||||
|
||||
String[] selectionArgs = selectionArgsList.toArray(new String[0]);
|
||||
|
||||
try (Cursor cursor = context.getContentResolver().query(
|
||||
CalendarContract.Events.CONTENT_URI,
|
||||
projection,
|
||||
selection,
|
||||
selection.toString(),
|
||||
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()) {
|
||||
|
|
@ -63,12 +121,10 @@ public class CalendarManager {
|
|||
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));
|
||||
}
|
||||
|
|
@ -84,7 +140,7 @@ public class CalendarManager {
|
|||
return deviceEvents;
|
||||
}
|
||||
|
||||
// --- ROBUST DATO-PARSING (Løser "null" problemet) ---
|
||||
// --- (formatEventForUI og mergeAndSort er uendret fra forrige versjon) ---
|
||||
public static void formatEventForUI(CalendarEvent event) {
|
||||
if (event.getRawDate() == null) return;
|
||||
|
||||
|
|
@ -102,32 +158,26 @@ public class CalendarManager {
|
|||
|
||||
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
|
||||
isoFmt.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
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());
|
||||
}
|
||||
|
|
@ -142,9 +192,6 @@ public class CalendarManager {
|
|||
} 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);
|
||||
|
|
|
|||
69
app/src/main/java/com/kbs/kbsintranett/CategoryAdapter.java
Normal file
69
app/src/main/java/com/kbs/kbsintranett/CategoryAdapter.java
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.util.List;
|
||||
|
||||
public class CategoryAdapter extends RecyclerView.Adapter<CategoryAdapter.ViewHolder> {
|
||||
|
||||
private List<String> categories;
|
||||
private String selectedCategory = "Alle"; // Standardvalg
|
||||
private OnCategoryClickListener listener;
|
||||
|
||||
public interface OnCategoryClickListener {
|
||||
void onCategoryClick(String category);
|
||||
}
|
||||
|
||||
public CategoryAdapter(List<String> categories, OnCategoryClickListener listener) {
|
||||
this.categories = categories;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_category, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
String category = categories.get(position);
|
||||
holder.name.setText(category);
|
||||
|
||||
if (category.equals(selectedCategory)) {
|
||||
// Valgt stil (Blå bakgrunn, hvit tekst)
|
||||
holder.name.setBackgroundResource(R.drawable.bg_category_selected);
|
||||
holder.name.setTextColor(Color.WHITE);
|
||||
} else {
|
||||
// Ikke valgt stil (Hvit bakgrunn, mørk tekst)
|
||||
holder.name.setBackgroundResource(R.drawable.bg_category_unselected);
|
||||
holder.name.setTextColor(Color.parseColor("#333333"));
|
||||
}
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
selectedCategory = category;
|
||||
notifyDataSetChanged(); // Oppdater alle for å flytte markering
|
||||
listener.onCategoryClick(category);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return categories.size();
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView name;
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
name = view.findViewById(R.id.category_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,60 +2,177 @@ package com.kbs.kbsintranett;
|
|||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class FormsListFragment extends Fragment {
|
||||
|
||||
private LinearLayout formsContainer;
|
||||
private ProgressBar progressBar;
|
||||
private TextView errorText;
|
||||
|
||||
private static final Pattern TITLE_NUMBER_PATTERN = Pattern.compile("^(\\d+)[.\\s-]+\\s*(.*)");
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_forms_list, container, false);
|
||||
LinearLayout formsContainer = view.findViewById(R.id.forms_container);
|
||||
formsContainer = view.findViewById(R.id.forms_container);
|
||||
|
||||
// Legger til knappene for de ulike skjemaene
|
||||
addFormButton(formsContainer, "1. Ansatteopplysninger", 1);
|
||||
addFormButton(formsContainer, "4. RUH (Rapport om uønsket hendelse)", 4);
|
||||
addFormButton(formsContainer, "9. Sikkerhetskurs / Kompetansebevis", 9);
|
||||
addFormButton(formsContainer, "10. HMS-bekreftelse", 10);
|
||||
addFormButton(formsContainer, "11. Egenmelding", 11);
|
||||
addFormButton(formsContainer, "12. Sjekkliste for firmabil", 12);
|
||||
addFormButton(formsContainer, "14. SJA (Sikker Jobbanalyse)", 14);
|
||||
addFormButton(formsContainer, "15. Fraværsvarsel", 15);
|
||||
addFormButton(formsContainer, "16. Refusjon utlegg", 16);
|
||||
addFormButton(formsContainer, "21. Forberedelse til medarbeidersamtale", 21);
|
||||
addFormButton(formsContainer, "22. Medarbeiderundersøkelse", 22);
|
||||
progressBar = new ProgressBar(getContext());
|
||||
LinearLayout.LayoutParams progressParams = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
progressParams.gravity = Gravity.CENTER;
|
||||
progressBar.setLayoutParams(progressParams);
|
||||
formsContainer.addView(progressBar);
|
||||
|
||||
errorText = new TextView(getContext());
|
||||
errorText.setTextColor(Color.RED);
|
||||
errorText.setVisibility(View.GONE);
|
||||
errorText.setPadding(20, 20, 20, 20);
|
||||
formsContainer.addView(errorText);
|
||||
|
||||
fetchFormsList();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void fetchFormsList() {
|
||||
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
|
||||
@Override
|
||||
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
|
||||
if (!isAdded()) return;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
List<GravityForm> activeForms = new ArrayList<>();
|
||||
|
||||
for (GravityForm form : response.body().values()) {
|
||||
// 1. Sjekk om skjemaet er aktivt (Bruker nå metoden i GravityForm)
|
||||
if (form.getIsActive()) {
|
||||
activeForms.add(form);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Sorter basert på tallet i tittelen
|
||||
Collections.sort(activeForms, new Comparator<GravityForm>() {
|
||||
@Override
|
||||
public int compare(GravityForm f1, GravityForm f2) {
|
||||
int num1 = extractNumber(f1.title);
|
||||
int num2 = extractNumber(f2.title);
|
||||
return Integer.compare(num1, num2);
|
||||
}
|
||||
});
|
||||
|
||||
populateList(activeForms);
|
||||
|
||||
} else {
|
||||
String msg = "Kunne ikke hente skjemaer. Kode: " + response.code();
|
||||
if (response.code() == 401 || response.code() == 403) {
|
||||
msg += "\n(Mangler tilgang. Er du admin?)";
|
||||
}
|
||||
showError(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
|
||||
if (!isAdded()) return;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
showError("Nettverksfeil: " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void populateList(List<GravityForm> forms) {
|
||||
formsContainer.removeAllViews();
|
||||
|
||||
if (forms.isEmpty()) {
|
||||
showError("Ingen aktive skjemaer funnet.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (GravityForm form : forms) {
|
||||
// FIX: form.id er allerede en int i GravityForm.java, så vi trenger ikke parse
|
||||
int formId = form.id;
|
||||
String cleanTitle = cleanTitle(form.title);
|
||||
addFormButton(formsContainer, cleanTitle, formId);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFormButton(LinearLayout container, String title, int formId) {
|
||||
Button btn = new Button(getContext());
|
||||
btn.setText(title);
|
||||
btn.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||
btn.setBackgroundColor(Color.parseColor("#0069B3"));
|
||||
btn.setTextColor(Color.WHITE);
|
||||
btn.setPadding(30, 30, 30, 30);
|
||||
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.setMargins(0, 0, 0, 20); // Litt avstand mellom knappene
|
||||
params.setMargins(0, 0, 0, 20);
|
||||
btn.setLayoutParams(params);
|
||||
|
||||
btn.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("formId", formId);
|
||||
// HER VAR FEILEN: Endret R.id.nav_forms til riktig action ID
|
||||
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
||||
});
|
||||
|
||||
container.addView(btn);
|
||||
}
|
||||
|
||||
private void showError(String message) {
|
||||
if (formsContainer == null) return;
|
||||
formsContainer.removeAllViews();
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setText(message);
|
||||
tv.setTextColor(Color.RED);
|
||||
tv.setTextSize(16);
|
||||
formsContainer.addView(tv);
|
||||
}
|
||||
|
||||
private int extractNumber(String title) {
|
||||
if (title == null) return 9999;
|
||||
Matcher m = TITLE_NUMBER_PATTERN.matcher(title.trim());
|
||||
if (m.find()) {
|
||||
try {
|
||||
return Integer.parseInt(m.group(1));
|
||||
} catch (NumberFormatException e) {
|
||||
return 9999;
|
||||
}
|
||||
}
|
||||
return 9999;
|
||||
}
|
||||
|
||||
private String cleanTitle(String title) {
|
||||
if (title == null) return "";
|
||||
Matcher m = TITLE_NUMBER_PATTERN.matcher(title.trim());
|
||||
if (m.find()) {
|
||||
return m.group(2);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
|
@ -42,13 +42,15 @@ public class GravityField {
|
|||
@SerializedName("content")
|
||||
public String content;
|
||||
|
||||
// --- BRUKER ADAPTEREN HER ---
|
||||
@JsonAdapter(InputsAdapter.class)
|
||||
@SerializedName("inputs")
|
||||
public List<GravityField> inputs;
|
||||
// ---------------------------
|
||||
|
||||
@SerializedName("isHidden")
|
||||
public boolean isHidden;
|
||||
|
||||
// NYTT: For å sjekke om feltet er Read Only (f.eks dato i refusjon)
|
||||
@SerializedName("gwreadonly_enable")
|
||||
public boolean readOnly;
|
||||
|
||||
|
|
@ -63,32 +65,19 @@ public class GravityField {
|
|||
public String gpnfForm;
|
||||
|
||||
public static class Choice {
|
||||
@SerializedName("text")
|
||||
public String text;
|
||||
|
||||
@SerializedName("value")
|
||||
public String value;
|
||||
@SerializedName("text") public String text;
|
||||
@SerializedName("value") public String value;
|
||||
}
|
||||
|
||||
public static class ConditionalLogic {
|
||||
@SerializedName("actionType")
|
||||
public String actionType;
|
||||
|
||||
@SerializedName("logicType")
|
||||
public String logicType;
|
||||
|
||||
@SerializedName("rules")
|
||||
public List<Rule> rules;
|
||||
@SerializedName("actionType") public String actionType;
|
||||
@SerializedName("logicType") public String logicType;
|
||||
@SerializedName("rules") public List<Rule> rules;
|
||||
}
|
||||
|
||||
public static class Rule {
|
||||
@SerializedName("fieldId")
|
||||
public String fieldId;
|
||||
|
||||
@SerializedName("operator")
|
||||
public String operator;
|
||||
|
||||
@SerializedName("value")
|
||||
public String value;
|
||||
@SerializedName("fieldId") public String fieldId;
|
||||
@SerializedName("operator") public String operator;
|
||||
@SerializedName("value") public String value;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,9 +13,17 @@ public class GravityForm {
|
|||
@SerializedName("description")
|
||||
public String description;
|
||||
|
||||
// Endret til Object for å være robust mot både "1" (String) og 1 (Int) fra API
|
||||
@SerializedName("is_active")
|
||||
public String isActive; // "1" = Aktiv, "0" = Inaktiv
|
||||
public Object isActive;
|
||||
|
||||
@SerializedName("fields")
|
||||
public List<GravityField> fields;
|
||||
|
||||
// Hjelpemetode for å sjekke om skjemaet er aktivt
|
||||
public boolean getIsActive() {
|
||||
if (isActive == null) return false;
|
||||
String s = isActive.toString();
|
||||
return "1".equals(s) || "true".equalsIgnoreCase(s);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,8 +18,12 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.work.PeriodicWorkRequest;
|
||||
import androidx.work.WorkManager;
|
||||
import java.text.SimpleDateFormat;
|
||||
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;
|
||||
|
|
@ -33,16 +37,19 @@ public class HomeFragment extends Fragment {
|
|||
@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)
|
||||
// Prøv å laste kalender på nytt (nå potensielt med personlig kalender)
|
||||
if (calendarRecycler != null) {
|
||||
fetchCalendarEvents(calendarRecycler);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Start bakgrunnsjobb for varsling (Hvert 15. minutt)
|
||||
// Start bakgrunnsjobb for varsling (kjører hver 15. minutt)
|
||||
startNotificationWorker();
|
||||
}
|
||||
|
||||
|
|
@ -56,18 +63,19 @@ public class HomeFragment extends Fragment {
|
|||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// Profil-knapp
|
||||
// 0. Profil-knapp
|
||||
View profileBtn = view.findViewById(R.id.btn_profile);
|
||||
if (profileBtn != null) {
|
||||
profileBtn.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.navigation_profile));
|
||||
}
|
||||
|
||||
// Kalender oppsett
|
||||
// 1. Kalender oppsett
|
||||
calendarRecycler = view.findViewById(R.id.recycler_calendar);
|
||||
calendarRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
// Sett tom adapter midlertidig
|
||||
calendarRecycler.setAdapter(new CalendarAdapter(new ArrayList<>(), event -> {}));
|
||||
|
||||
// "Se alle" knapp
|
||||
// "Se alle" knapp for kalender
|
||||
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));
|
||||
|
|
@ -88,18 +96,29 @@ public class HomeFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// Nyheter
|
||||
// 2. Nyheter oppsett
|
||||
RecyclerView newsRecycler = view.findViewById(R.id.recycler_news);
|
||||
newsRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
newsRecycler.setNestedScrollingEnabled(false);
|
||||
newsRecycler.setAdapter(new NewsAdapter(new ArrayList<>()));
|
||||
// Sett tom adapter midlertidig
|
||||
newsRecycler.setAdapter(new NewsAdapter(new ArrayList<>(), item -> {}));
|
||||
|
||||
// "Se alle" knapp for nyheter
|
||||
TextView viewAllNews = view.findViewById(R.id.btn_view_all_news);
|
||||
if (viewAllNews != null) {
|
||||
viewAllNews.setOnClickListener(v -> {
|
||||
Navigation.findNavController(view).navigate(R.id.action_home_to_newsFull);
|
||||
});
|
||||
}
|
||||
|
||||
fetchNewsFromWordpress(newsRecycler);
|
||||
}
|
||||
|
||||
private void fetchCalendarEvents(RecyclerView recyclerView) {
|
||||
// 1. Hent personlige hendelser først
|
||||
// 1. Hent personlige hendelser først (fra CalendarManager)
|
||||
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext());
|
||||
|
||||
// 2. Hent API-hendelser fra WordPress
|
||||
WordPressApiService apiService = RetrofitClient.getApiService();
|
||||
apiService.getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
|
||||
@Override
|
||||
|
|
@ -114,13 +133,24 @@ public class HomeFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// Flett lister
|
||||
// 3. Flett listene (API + Personlig) og sorter
|
||||
List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
||||
|
||||
// Vis kun topp 5
|
||||
// 4. Filtrer ut hendelser som har passert (vis kun fremtidige + i dag)
|
||||
// (CalendarManager henter 1 år bakover, så vi må filtrere for "Topp 5 kommende")
|
||||
List<CalendarEvent> upcomingEvents = new ArrayList<>();
|
||||
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
||||
|
||||
for (CalendarEvent e : merged) {
|
||||
if (e.getRawDate() != null && e.getRawDate().compareTo(today) >= 0) {
|
||||
upcomingEvents.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Vis kun de 5 første av de kommende
|
||||
List<CalendarEvent> top5 = new ArrayList<>();
|
||||
for(int i=0; i<Math.min(merged.size(), 5); i++) {
|
||||
top5.add(merged.get(i));
|
||||
for(int i=0; i<Math.min(upcomingEvents.size(), 5); i++) {
|
||||
top5.add(upcomingEvents.get(i));
|
||||
}
|
||||
|
||||
recyclerView.setAdapter(new CalendarAdapter(top5, event -> {
|
||||
|
|
@ -135,6 +165,7 @@ public class HomeFragment extends Fragment {
|
|||
// Hvis API feiler, vis bare personlige events hvis vi har noen
|
||||
if (!deviceEvents.isEmpty()) {
|
||||
List<CalendarEvent> top5 = new ArrayList<>();
|
||||
// Filtrer og plukk topp 5 fra lokale også
|
||||
for(int i=0; i<Math.min(deviceEvents.size(), 5); i++) top5.add(deviceEvents.get(i));
|
||||
|
||||
recyclerView.setAdapter(new CalendarAdapter(top5, event -> {
|
||||
|
|
@ -142,7 +173,6 @@ public class HomeFragment extends Fragment {
|
|||
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));
|
||||
|
|
@ -151,48 +181,55 @@ public class HomeFragment extends Fragment {
|
|||
});
|
||||
}
|
||||
|
||||
private void fetchNewsFromWordpress(RecyclerView recyclerView) {
|
||||
WordPressApiService apiService = RetrofitClient.getApiService();
|
||||
// Bruker getPosts som henter 5-10 innlegg med ?_embed
|
||||
apiService.getPosts().enqueue(new Callback<List<WpPost>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
||||
if (getContext() == null) return;
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
List<WpPost> wpPosts = response.body();
|
||||
|
||||
// Datoformatering
|
||||
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
rawFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
|
||||
targetFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
for (WpPost post : wpPosts) {
|
||||
try {
|
||||
Date date = rawFormat.parse(post.date);
|
||||
post.date = targetFormat.format(date); // Setter pen dato
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
// Sett adapter med Click Listener
|
||||
NewsAdapter adapter = new NewsAdapter(wpPosts, post -> {
|
||||
// Naviger til detaljvisning og send med post-objektet
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("post_data", post); // WpPost er nå Serializable
|
||||
Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsDetail, bundle);
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
||||
if (getContext() == null) return;
|
||||
// Ved feil, sett tom liste (eller vis feilmelding)
|
||||
recyclerView.setAdapter(new NewsAdapter(new ArrayList<>(), null));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void startNotificationWorker() {
|
||||
// Kjører en jobb hvert 15. minutt for å sjekke om det er nye møter
|
||||
// Kjører en jobb hvert 15. minutt for å sjekke om det er nye møter i HMS-kalenderen
|
||||
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) {
|
||||
// [Lim inn koden for nyheter fra forrige svar her, den var OK]
|
||||
WordPressApiService apiService = RetrofitClient.getApiService();
|
||||
apiService.getPosts().enqueue(new Callback<List<WpPost>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
||||
if (getContext() == null) return;
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
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"));
|
||||
|
||||
for (WpPost post : wpPosts) {
|
||||
String formattedDate = post.date;
|
||||
try {
|
||||
java.util.Date date = rawFormat.parse(post.date);
|
||||
formattedDate = targetFormat.format(date);
|
||||
} catch (java.text.ParseException e) {}
|
||||
newsList.add(new NewsItem(post.getTitleStr(), post.getExcerptStr(), "Publisert: " + formattedDate));
|
||||
}
|
||||
recyclerView.setAdapter(new NewsAdapter(newsList));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
||||
if (getContext() == null) return;
|
||||
List<NewsItem> errorList = new ArrayList<>();
|
||||
errorList.add(new NewsItem("Kunne ikke laste nyheter", "Sjekk nettverket ditt.", "System"));
|
||||
recyclerView.setAdapter(new NewsAdapter(errorList));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
30
app/src/main/java/com/kbs/kbsintranett/InputsAdapter.java
Normal file
30
app/src/main/java/com/kbs/kbsintranett/InputsAdapter.java
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class InputsAdapter implements JsonDeserializer<List<GravityField>> {
|
||||
@Override
|
||||
public List<GravityField> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
if (json.isJsonNull()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// Fikser krasjen: Hvis Gravity Forms sender "" i stedet for [], returner tom liste
|
||||
if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
if (json.isJsonArray()) {
|
||||
List<GravityField> list = new ArrayList<>();
|
||||
for (JsonElement e : json.getAsJsonArray()) {
|
||||
list.add(context.deserialize(e, GravityField.class));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,17 +3,34 @@ package com.kbs.kbsintranett;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
||||
import java.util.List;
|
||||
|
||||
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
|
||||
|
||||
private List<NewsItem> newsList;
|
||||
private List<WpPost> posts;
|
||||
private OnItemClickListener listener; // NYTT
|
||||
|
||||
public NewsAdapter(List<NewsItem> newsList) {
|
||||
this.newsList = newsList;
|
||||
// Interface for klikk
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(WpPost post);
|
||||
}
|
||||
|
||||
// Oppdatert konstruktør
|
||||
public NewsAdapter(List<WpPost> posts, OnItemClickListener listener) {
|
||||
this.posts = posts;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
// Overload for bakoverkompatibilitet (hvis du ikke sender listener)
|
||||
public NewsAdapter(List<WpPost> posts) {
|
||||
this.posts = posts;
|
||||
this.listener = null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
@ -25,24 +42,62 @@ public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
NewsItem item = newsList.get(position);
|
||||
holder.title.setText(item.getTitle());
|
||||
holder.excerpt.setText(item.getExcerpt());
|
||||
holder.author.setText("Av: " + item.getAuthor());
|
||||
WpPost post = posts.get(position);
|
||||
|
||||
holder.title.setText(post.getTitleStr());
|
||||
holder.excerpt.setText(post.getExcerptStr());
|
||||
holder.date.setText(post.date);
|
||||
|
||||
String cat = post.getCategoryName();
|
||||
if (!cat.isEmpty()) {
|
||||
holder.category.setText(cat);
|
||||
holder.category.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.category.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
String imageUrl = post.getFeaturedImageUrl();
|
||||
if (imageUrl != null && !imageUrl.isEmpty()) {
|
||||
holder.image.setVisibility(View.VISIBLE);
|
||||
Glide.with(holder.itemView.getContext())
|
||||
.load(imageUrl)
|
||||
.transition(DrawableTransitionOptions.withCrossFade())
|
||||
.centerCrop()
|
||||
.into(holder.image);
|
||||
} else {
|
||||
holder.image.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// NYTT: Håndter klikk
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onItemClick(post);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return newsList.size();
|
||||
return posts.size();
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView title, excerpt, author;
|
||||
TextView title, excerpt, date, category;
|
||||
ImageView image;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
title = view.findViewById(R.id.news_title);
|
||||
excerpt = view.findViewById(R.id.news_excerpt);
|
||||
author = view.findViewById(R.id.news_author);
|
||||
date = view.findViewById(R.id.news_date);
|
||||
category = view.findViewById(R.id.news_category);
|
||||
image = view.findViewById(R.id.news_image);
|
||||
}
|
||||
}
|
||||
|
||||
// NYTT: Metode for å oppdatere listen etter filtrering
|
||||
public void updateList(List<WpPost> newPosts) {
|
||||
this.posts = newPosts;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
public class NewsDetailFragment extends Fragment {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_news_detail, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// Hent data fra argumentene (sendt fra HomeFragment/NewsFullFragment)
|
||||
if (getArguments() != null) {
|
||||
WpPost post = (WpPost) getArguments().getSerializable("post_data");
|
||||
if (post != null) {
|
||||
setupViews(view, post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupViews(View view, WpPost post) {
|
||||
Toolbar toolbar = view.findViewById(R.id.detail_toolbar);
|
||||
toolbar.setNavigationOnClickListener(v -> Navigation.findNavController(view).navigateUp());
|
||||
|
||||
ImageView image = view.findViewById(R.id.detail_image);
|
||||
TextView title = view.findViewById(R.id.detail_title);
|
||||
TextView category = view.findViewById(R.id.detail_category);
|
||||
TextView date = view.findViewById(R.id.detail_date);
|
||||
TextView author = view.findViewById(R.id.detail_author); // NY
|
||||
TextView content = view.findViewById(R.id.detail_content);
|
||||
|
||||
String imgUrl = post.getFeaturedImageUrl();
|
||||
if (imgUrl != null) {
|
||||
Glide.with(this).load(imgUrl).centerCrop().into(image);
|
||||
} else {
|
||||
image.setBackgroundColor(getResources().getColor(android.R.color.darker_gray));
|
||||
}
|
||||
|
||||
title.setText(post.getTitleStr());
|
||||
category.setText(post.getCategoryName());
|
||||
date.setText("Publisert: " + post.date);
|
||||
|
||||
// NYTT: Sett forfatter
|
||||
author.setText("Av: " + post.getAuthorName());
|
||||
|
||||
content.setText(Html.fromHtml(post.getContentStr(), Html.FROM_HTML_MODE_COMPACT));
|
||||
content.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
}
|
||||
}
|
||||
144
app/src/main/java/com/kbs/kbsintranett/NewsFullFragment.java
Normal file
144
app/src/main/java/com/kbs/kbsintranett/NewsFullFragment.java
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
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.Toast;
|
||||
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.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class NewsFullFragment extends Fragment {
|
||||
|
||||
private RecyclerView recyclerViewNews;
|
||||
private RecyclerView recyclerViewCategories;
|
||||
private ProgressBar progressBar;
|
||||
private NewsAdapter newsAdapter;
|
||||
private List<WpPost> allPosts = new ArrayList<>(); // Holder på ALLE postene
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_news_full, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
recyclerViewNews = view.findViewById(R.id.recycler_news_full);
|
||||
recyclerViewCategories = view.findViewById(R.id.recycler_categories);
|
||||
progressBar = view.findViewById(R.id.loading_news_full);
|
||||
ImageView backBtn = view.findViewById(R.id.btn_back_news);
|
||||
|
||||
// Setup Nyhetsliste
|
||||
recyclerViewNews.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
// Setup Kategorier (Horisontal)
|
||||
recyclerViewCategories.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
setupCategories();
|
||||
|
||||
backBtn.setOnClickListener(v -> Navigation.findNavController(view).navigateUp());
|
||||
|
||||
fetchAllNews();
|
||||
}
|
||||
|
||||
private void setupCategories() {
|
||||
// Listen over kategorier du ønsket
|
||||
List<String> categories = Arrays.asList(
|
||||
"Alle", // Standard vis alt
|
||||
"Avtaler og invitasjoner", "BHT", "Bilhold", "Cordel",
|
||||
"Ferieavvikling", "Fest og moro", "Generell drift",
|
||||
"HMS", "IT og sikkerhet", "Miljøfyrtårn", "Møtereferat", "SMX"
|
||||
);
|
||||
|
||||
CategoryAdapter catAdapter = new CategoryAdapter(categories, selectedCategory -> {
|
||||
filterNews(selectedCategory);
|
||||
});
|
||||
recyclerViewCategories.setAdapter(catAdapter);
|
||||
}
|
||||
|
||||
private void fetchAllNews() {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
// Hent 50 siste (bør holde for en "Siste nytt" liste, ellers må vi paginere)
|
||||
RetrofitClient.getApiService().getAllPosts().enqueue(new Callback<List<WpPost>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
||||
if (!isAdded()) return;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
allPosts = response.body();
|
||||
formatDates(allPosts);
|
||||
|
||||
// Vis alle i starten
|
||||
newsAdapter = new NewsAdapter(new ArrayList<>(allPosts), post -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("post_data", post);
|
||||
Navigation.findNavController(getView()).navigate(R.id.action_newsFull_to_newsDetail, bundle);
|
||||
});
|
||||
recyclerViewNews.setAdapter(newsAdapter);
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Klarte ikke laste nyheter", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
||||
if (!isAdded()) return;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
Toast.makeText(getContext(), "Nettverksfeil", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void filterNews(String category) {
|
||||
if (newsAdapter == null) return;
|
||||
|
||||
List<WpPost> filteredList = new ArrayList<>();
|
||||
|
||||
if (category.equals("Alle")) {
|
||||
filteredList.addAll(allPosts);
|
||||
} else {
|
||||
for (WpPost post : allPosts) {
|
||||
// Vi sjekker om kategorinavnet matcher
|
||||
if (post.getCategoryName().equals(category)) {
|
||||
filteredList.add(post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Oppdater adapteren med den filtrerte listen
|
||||
newsAdapter.updateList(filteredList);
|
||||
}
|
||||
|
||||
private void formatDates(List<WpPost> posts) {
|
||||
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
rawFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
|
||||
targetFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
for (WpPost post : posts) {
|
||||
try {
|
||||
Date date = rawFormat.parse(post.date);
|
||||
post.date = targetFormat.format(date);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,8 +16,8 @@ import retrofit2.http.PartMap;
|
|||
import retrofit2.http.Query;
|
||||
|
||||
public interface WordPressApiService {
|
||||
// 1. Hent nyheter
|
||||
@GET("wp-json/wp/v2/posts?per_page=5")
|
||||
// 1. Hent nyheter - ENDRET: Lagt til &_embed for å få bilde og kategori
|
||||
@GET("wp-json/wp/v2/posts?per_page=10&_embed")
|
||||
Call<List<WpPost>> getPosts();
|
||||
|
||||
// 2. Hent et spesifikt skjema med ID
|
||||
|
|
@ -57,7 +57,11 @@ public interface WordPressApiService {
|
|||
@Query("paging[page_size]") int pageSize
|
||||
);
|
||||
|
||||
// 9. HENT ÉN ENKELT INNSENDING (Ny! Brukes for å hente detaljer fra underskjema)
|
||||
// 9. HENT ÉN ENKELT INNSENDING
|
||||
@GET("wp-json/gf/v2/entries/{entry_id}")
|
||||
Call<JsonElement> getSingleEntry(@Path("entry_id") String entryId);
|
||||
|
||||
// 10. HENT ALLE NYHETER (F.eks 50 stk) - Brukes av "Se alle" siden
|
||||
@GET("wp-json/wp/v2/posts?per_page=50&_embed")
|
||||
Call<List<WpPost>> getAllPosts();
|
||||
}
|
||||
|
|
@ -1,31 +1,106 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class WpPost {
|
||||
// WordPress sender tittelen som et objekt: "title": { "rendered": "Overskrift" }
|
||||
public class WpPost implements Serializable {
|
||||
@SerializedName("title")
|
||||
public Rendered title;
|
||||
|
||||
@SerializedName("excerpt")
|
||||
public Rendered excerpt;
|
||||
|
||||
@SerializedName("content")
|
||||
public Rendered content;
|
||||
|
||||
@SerializedName("date")
|
||||
public String date;
|
||||
|
||||
// Hjelpeklasse for å hente ut teksten inni "rendered"
|
||||
public static class Rendered {
|
||||
@SerializedName("_embedded")
|
||||
public Embedded embedded;
|
||||
|
||||
public static class Rendered implements Serializable {
|
||||
@SerializedName("rendered")
|
||||
public String renderedString;
|
||||
}
|
||||
|
||||
// En hjelpemetode for å få ren tekst ut (fjerner HTML-koder hvis nødvendig)
|
||||
public static class Embedded implements Serializable {
|
||||
@SerializedName("wp:featuredmedia")
|
||||
public List<Media> mediaList;
|
||||
|
||||
@SerializedName("wp:term")
|
||||
public List<List<Term>> termList;
|
||||
|
||||
// NYTT: Forfatter-liste
|
||||
@SerializedName("author")
|
||||
public List<Author> authorList;
|
||||
}
|
||||
|
||||
public static class Media implements Serializable {
|
||||
@SerializedName("source_url")
|
||||
public String sourceUrl;
|
||||
}
|
||||
|
||||
public static class Term implements Serializable {
|
||||
@SerializedName("name")
|
||||
public String name;
|
||||
}
|
||||
|
||||
// NYTT: Forfatter-klasse
|
||||
public static class Author implements Serializable {
|
||||
@SerializedName("name")
|
||||
public String name;
|
||||
}
|
||||
|
||||
public String getTitleStr() {
|
||||
return title != null ? title.renderedString : "Uten tittel";
|
||||
}
|
||||
|
||||
public String getExcerptStr() {
|
||||
// En enkel rensing av HTML-tags (f.eks <p>)
|
||||
return excerpt != null ? android.text.Html.fromHtml(excerpt.renderedString, android.text.Html.FROM_HTML_MODE_COMPACT).toString() : "";
|
||||
return excerpt != null ?
|
||||
android.text.Html.fromHtml(excerpt.renderedString, android.text.Html.FROM_HTML_MODE_COMPACT).toString().trim() : "";
|
||||
}
|
||||
|
||||
public String getContentStr() {
|
||||
return content != null ? content.renderedString : "";
|
||||
}
|
||||
|
||||
public String getFeaturedImageUrl() {
|
||||
if (embedded != null && embedded.mediaList != null && !embedded.mediaList.isEmpty()) {
|
||||
return embedded.mediaList.get(0).sourceUrl;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// NYTT: Hent forfatternavn
|
||||
public String getAuthorName() {
|
||||
if (embedded != null && embedded.authorList != null && !embedded.authorList.isEmpty()) {
|
||||
return embedded.authorList.get(0).name;
|
||||
}
|
||||
return "Ukjent"; // Fallback
|
||||
}
|
||||
|
||||
public String getCategoryName() {
|
||||
if (embedded != null && embedded.termList != null && !embedded.termList.isEmpty()) {
|
||||
List<Term> categories = embedded.termList.get(0);
|
||||
if (categories == null || categories.isEmpty()) return "";
|
||||
|
||||
List<String> priorityCategories = Arrays.asList(
|
||||
"Avtaler og invitasjoner", "BHT", "Bilhold", "Cordel",
|
||||
"Ferieavvikling", "Fest og moro", "Generell drift",
|
||||
"HMS", "IT og sikkerhet", "Miljøfyrtårn", "Møtereferat", "SMX"
|
||||
);
|
||||
|
||||
for (Term term : categories) {
|
||||
if (priorityCategories.contains(term.name)) return term.name;
|
||||
}
|
||||
for (Term term : categories) {
|
||||
if (term.name.contains("Alle ansatte")) return "Til info";
|
||||
}
|
||||
return categories.get(0).name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
5
app/src/main/res/drawable/bg_category_selected.xml
Normal file
5
app/src/main/res/drawable/bg_category_selected.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/kbs_logo_blue" />
|
||||
<corners android:radius="20dp" />
|
||||
</shape>
|
||||
6
app/src/main/res/drawable/bg_category_unselected.xml
Normal file
6
app/src/main/res/drawable/bg_category_unselected.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#FFFFFF" />
|
||||
<stroke android:width="1dp" android:color="#DDDDDD" />
|
||||
<corners android:radius="20dp" />
|
||||
</shape>
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
android:textStyle="bold"
|
||||
android:textColor="@color/kbs_muted_blue_gray"
|
||||
android:layout_centerVertical="true"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_profile"
|
||||
android:layout_width="40dp"
|
||||
|
|
@ -69,15 +70,34 @@
|
|||
android:scrollbars="vertical"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="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="Siste nytt"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginStart="8dp"/>
|
||||
android:textColor="@color/black"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_view_all_news"
|
||||
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_news"
|
||||
|
|
|
|||
101
app/src/main/res/layout/fragment_news_detail.xml
Normal file
101
app/src/main/res/layout/fragment_news_detail.xml
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
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:background="@android:color/white">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250dp"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
||||
app:contentScrim="@color/kbs_logo_blue">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_collapseMode="parallax" />
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/detail_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_collapseMode="pin"
|
||||
app:navigationIcon="@android:drawable/ic_menu_revert" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_category"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/kbs_logo_accent_red"
|
||||
android:textStyle="bold"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@android:color/black"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#888888"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginEnd="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_author"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#888888"
|
||||
android:textStyle="italic"
|
||||
android:textSize="12sp"
|
||||
android:text="Av: Forfatter"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#333333"
|
||||
android:textSize="16sp"
|
||||
android:lineSpacingExtra="4dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
61
app/src/main/res/layout/fragment_news_full.xml
Normal file
61
app/src/main/res/layout/fragment_news_full.xml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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="@android:color/white"
|
||||
android:elevation="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_back_news"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@android:drawable/ic_menu_revert"
|
||||
android:layout_centerVertical="true"
|
||||
android:contentDescription="Tilbake"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Siste nytt"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@android:color/black"
|
||||
android:layout_centerInParent="true"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_categories"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="none"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_news_full"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingHorizontal="4dp"
|
||||
android:clipToPadding="false"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_news_full"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
13
app/src/main/res/layout/item_category.xml
Normal file
13
app/src/main/res/layout/item_category.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/category_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Kategori"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@drawable/bg_category_unselected"
|
||||
android:textColor="#333333"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
|
@ -3,11 +3,24 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="2dp">
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="@android:color/white">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/news_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="200dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@android:drawable/ic_menu_gallery"
|
||||
android:background="#EEEEEE" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -15,30 +28,62 @@
|
|||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/news_category"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="KATEGORI"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/kbs_logo_accent_red"
|
||||
android:textAllCaps="true"
|
||||
android:letterSpacing="0.05"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/news_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Nyhets overskrift"
|
||||
android:textSize="18sp"
|
||||
android:text="Overskrift på nyhetssaken kommer her"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@android:color/black"/>
|
||||
android:textColor="@android:color/black"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:lineSpacingExtra="2dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/news_excerpt"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Her kommer ingressen..."
|
||||
android:textColor="@android:color/darker_gray"/>
|
||||
android:text="Her kommer en kort ingress som beskriver saken litt nærmere før man klikker seg inn..."
|
||||
android:textColor="#555555"
|
||||
android:textSize="14sp"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
android:src="@android:drawable/ic_menu_my_calendar"
|
||||
app:tint="#999999"
|
||||
android:layout_marginEnd="6dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/news_author"
|
||||
android:id="@+id/news_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="Skrevet av: Ole"
|
||||
android:text="23. Nov 2025"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"/>
|
||||
android:textColor="#999999"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
|
@ -22,9 +22,18 @@
|
|||
android:name="com.kbs.kbsintranett.HomeFragment"
|
||||
android:label="Hjem"
|
||||
tools:layout="@layout/fragment_home">
|
||||
|
||||
<action
|
||||
android:id="@+id/action_home_to_calendarFull"
|
||||
app:destination="@id/navigation_calendar_full" />
|
||||
|
||||
<action
|
||||
android:id="@+id/action_home_to_newsFull"
|
||||
app:destination="@id/navigation_news_full" />
|
||||
|
||||
<action
|
||||
android:id="@+id/action_home_to_newsDetail"
|
||||
app:destination="@id/navigation_news_detail" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
|
@ -33,12 +42,27 @@
|
|||
android:label="Kalender"
|
||||
tools:layout="@layout/fragment_calendar_full" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_news_full"
|
||||
android:name="com.kbs.kbsintranett.NewsFullFragment"
|
||||
android:label="Nyheter"
|
||||
tools:layout="@layout/fragment_news_full">
|
||||
<action
|
||||
android:id="@+id/action_newsFull_to_newsDetail"
|
||||
app:destination="@id/navigation_news_detail" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_news_detail"
|
||||
android:name="com.kbs.kbsintranett.NewsDetailFragment"
|
||||
android:label="Nyhet"
|
||||
tools:layout="@layout/fragment_news_detail" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_forms"
|
||||
android:name="com.kbs.kbsintranett.FormsListFragment"
|
||||
android:label="Skjemaer"
|
||||
tools:layout="@layout/fragment_forms">
|
||||
<action
|
||||
tools:layout="@layout/fragment_forms_list"> <action
|
||||
android:id="@+id/action_formsListFragment_to_formsDetailFragment"
|
||||
app:destination="@id/navigation_forms_detail" />
|
||||
</fragment>
|
||||
|
|
|
|||
1921
hele_prosjektet.txt
1921
hele_prosjektet.txt
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue