Før håndbok

This commit is contained in:
ErolHaagenrud 2025-12-12 14:03:52 +01:00
parent b74c8715ef
commit e4affef594
7 changed files with 6012 additions and 74 deletions

View file

@ -4,14 +4,12 @@ plugins {
android {
namespace = "com.kbs.kbsintranett"
compileSdk {
version = release(36)
}
compileSdk = 34
defaultConfig {
applicationId = "com.kbs.kbsintranett"
minSdk = 28
targetSdk = 36
targetSdk = 34
versionCode = 1
versionName = "1.0"
@ -28,6 +26,7 @@ android {
}
}
compileOptions {
// ENDRET: Oppgradert til Java 11 for å fikse build warnings
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
@ -47,8 +46,8 @@ dependencies {
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.google.code.gson:gson:2.10.1")
// Navigation Component (KORRIGERT FOR KOTLIN DSL)
val navVersion = "2.8.5" // Oppdatert til en nyere, stabil versjon
// Navigation Component
val navVersion = "2.8.5"
implementation("androidx.navigation:navigation-fragment:$navVersion")
implementation("androidx.navigation:navigation-ui:$navVersion")
@ -57,4 +56,7 @@ dependencies {
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
implementation("androidx.work:work-runtime:2.9.0")
// Swipe Refresh Layout
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
}

View file

@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.kbs.kbsintranett">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

View file

@ -15,12 +15,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
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;
@ -33,20 +33,24 @@ public class FormsListFragment extends Fragment {
private LinearLayout formsContainer;
private ProgressBar progressBar;
private TextView errorText;
private SwipeRefreshLayout swipeRefreshLayout;
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);
formsContainer = view.findViewById(R.id.forms_container);
formsContainer = view.findViewById(R.id.forms_container);
swipeRefreshLayout = view.findViewById(R.id.swipe_refresh);
// Opprett en ProgressBar manuelt for første gangs lasting
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());
@ -55,29 +59,47 @@ public class FormsListFragment extends Fragment {
errorText.setPadding(20, 20, 20, 20);
formsContainer.addView(errorText);
// Sett opp listener for swipe
swipeRefreshLayout.setOnRefreshListener(() -> {
fetchFormsList();
});
// Hent data første gang
fetchFormsList();
return view;
}
private void fetchFormsList() {
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
// Skjul feilmelding før ny henting
if (errorText != null) errorText.setVisibility(View.GONE);
RetrofitClient.getApiService().getFormsList().enqueue(new Callback<List<GravityForm>>() {
@Override
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
public void onResponse(Call<List<GravityForm>> call, Response<List<GravityForm>> response) {
if (!isAdded()) return;
// Stopp lasting-indikatorer
progressBar.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
if (response.isSuccessful() && response.body() != null) {
List<GravityForm> allForms = response.body();
List<GravityForm> activeForms = new ArrayList<>();
for (GravityForm form : response.body().values()) {
// 1. Sjekk om skjemaet er aktivt (Bruker metoden i GravityForm)
for (GravityForm form : allForms) {
if (form.getIsActive()) {
// NYTT: Hardkodet filtrering av skjemaer som ikke skal vises i listen
// ID 10 = HMS-bekreftelse (Skal ligge i Håndbok/separat flyt)
// ID 18 = Refusjon-vedlegg (Er et underskjema som brukes av ID 16)
if (form.id == 10 || form.id == 18) {
continue;
}
activeForms.add(form);
}
}
// 2. Sorter basert tallet i tittelen
Collections.sort(activeForms, new Comparator<GravityForm>() {
@Override
public int compare(GravityForm f1, GravityForm f2) {
@ -86,22 +108,25 @@ public class FormsListFragment extends Fragment {
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?)";
msg += "\n(Mangler tilgang. Prøv å logge ut og inn igjen.)";
}
showError(msg);
}
}
@Override
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
public void onFailure(Call<List<GravityForm>> call, Throwable t) {
if (!isAdded()) return;
// Stopp lasting-indikatorer
progressBar.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
showError("Nettverksfeil: " + t.getMessage());
}
});
@ -116,7 +141,6 @@ public class FormsListFragment extends Fragment {
}
for (GravityForm form : forms) {
// FIX: form.id er allerede en int i GravityForm.java, vi trenger ikke parse
int formId = form.id;
String cleanTitle = cleanTitle(form.title);
addFormButton(formsContainer, cleanTitle, formId);
@ -147,6 +171,7 @@ public class FormsListFragment extends Fragment {
private void showError(String message) {
if (formsContainer == null) return;
formsContainer.removeAllViews();
TextView tv = new TextView(getContext());
tv.setText(message);
tv.setTextColor(Color.RED);

View file

@ -1,3 +1,4 @@
// FILSTI: app\src\main\java\com\kbs\kbsintranett\WordPressApiService.java
package com.kbs.kbsintranett;
import com.google.gson.JsonElement;
@ -16,12 +17,12 @@ import retrofit2.http.PartMap;
import retrofit2.http.Query;
public interface WordPressApiService {
// 1. Hent nyheter - ENDRET: Lagt til &_embed for å bilde og kategori
// 1. Hent nyheter
@GET("wp-json/wp/v2/posts?per_page=10&_embed")
Call<List<WpPost>> getPosts();
// 2. Hent et spesifikt skjema med ID
@GET("wp-json/gf/v2/forms/{id}")
// 2. Hent et spesifikt skjema med ID (Oppdatert til custom endpoint for tilgang)
@GET("wp-json/kbs/v1/forms/{id}")
Call<GravityForm> getForm(@Path("id") int formId);
// 3. SEND INN SKJEMA (JSON-data uten filer)
@ -32,9 +33,9 @@ public interface WordPressApiService {
@POST("wp-json/kbs/v1/login")
Call<LoginResponse> googleLogin(@Body LoginRequest request);
// 5. HENT LISTE AV SKJEMAER
@GET("wp-json/gf/v2/forms")
Call<Map<String, GravityForm>> getFormsListMap();
// 5. HENT LISTE AV SKJEMAER (Oppdatert til custom endpoint og List)
@GET("wp-json/kbs/v1/forms")
Call<List<GravityForm>> getFormsList();
// 6. SEND INN SKJEMA (MULTIPART - for filopplasting)
@Multipart

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout" android:layout_width="match_parent"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
@ -16,15 +17,22 @@
android:layout_marginBottom="20dp"
android:textColor="#333333"/>
<ScrollView
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/forms_container"
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/forms_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>

View file

@ -2728,62 +2728,179 @@ 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;
}
}
============================================================
@ -2870,13 +2987,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;
@ -2891,33 +3010,20 @@ 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;
}
}
@ -2939,11 +3045,19 @@ 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);
}
}
============================================================
@ -3201,6 +3315,40 @@ public class HomeFragment extends Fragment {
}
}
============================================================
FILSTI: app\src\main\java\com\kbs\kbsintranett\InputsAdapter.java
============================================================
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<>();
}
}
============================================================
FILSTI: app\src\main\java\com\kbs\kbsintranett\LoginFragment.java
============================================================

5756
hele_prosjektet.txt.old Normal file

File diff suppressed because it is too large Load diff