Før caching

This commit is contained in:
ErolHaagenrud 2025-12-18 13:27:39 +01:00
parent 91f8c2c0c7
commit 5497e68110
4 changed files with 91 additions and 86 deletions

39
app/google-services.json Normal file
View file

@ -0,0 +1,39 @@
{
"project_info": {
"project_number": "738325360287",
"project_id": "intranet-glogin-452614",
"storage_bucket": "intranet-glogin-452614.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:738325360287:android:c97082eedba86b85b43caa",
"android_client_info": {
"package_name": "com.kbs.kbsintranett"
}
},
"oauth_client": [
{
"client_id": "738325360287-cidl3plnqv9ei74vm9vm5muustj6eenb.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyC0vrXCWJNLzrgOk1ChWeFpYlqxKPqxUf0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "738325360287-cidl3plnqv9ei74vm9vm5muustj6eenb.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View file

@ -43,14 +43,15 @@ import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts; import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider; import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -102,11 +103,12 @@ public class FormsFragment extends Fragment {
private LinearLayout formContainer; private LinearLayout formContainer;
private LinearLayout historyContainer; private LinearLayout historyContainer;
private View historyWrapper; // Wrapper for historikk-modulen private View historyWrapper;
private TextView txtStatus; private TextView txtStatus;
private TextView lblHistory; private TextView lblHistory;
private ProgressBar loadingSpinner; private ProgressBar loadingSpinner;
private ImageView btnToggleHistory; private ImageView btnToggleHistory;
private Toolbar toolbar; // NYTT
// --- HOVEDSKJEMA STATE --- // --- HOVEDSKJEMA STATE ---
private Map<String, View> fieldWrappers = new HashMap<>(); private Map<String, View> fieldWrappers = new HashMap<>();
@ -118,7 +120,7 @@ public class FormsFragment extends Fragment {
private Map<String, View> childInputViews = new HashMap<>(); private Map<String, View> childInputViews = new HashMap<>();
private Map<String, Boolean> childRequiredFieldsMap = new HashMap<>(); private Map<String, Boolean> childRequiredFieldsMap = new HashMap<>();
private Map<String, Uri> childFileUploads = new HashMap<>(); private Map<String, Uri> childFileUploads = new HashMap<>();
// Lagring av Nested Entries
private List<NestedEntry> nestedEntries = new ArrayList<>(); private List<NestedEntry> nestedEntries = new ArrayList<>();
private LinearLayout nestedEntriesContainer; private LinearLayout nestedEntriesContainer;
private TextView totalAmountView; private TextView totalAmountView;
@ -184,12 +186,17 @@ public class FormsFragment extends Fragment {
lblHistory = view.findViewById(R.id.lbl_history); lblHistory = view.findViewById(R.id.lbl_history);
loadingSpinner = view.findViewById(R.id.loading_spinner); loadingSpinner = view.findViewById(R.id.loading_spinner);
// NYTT: Finn toolbar og sett listener
toolbar = view.findViewById(R.id.forms_toolbar);
if (toolbar != null) {
toolbar.setNavigationOnClickListener(v -> Navigation.findNavController(view).navigateUp());
}
btnToggleHistory = view.findViewById(R.id.btn_toggle_history); btnToggleHistory = view.findViewById(R.id.btn_toggle_history);
if (btnToggleHistory != null) { if (btnToggleHistory != null) {
btnToggleHistory.setOnClickListener(v -> toggleHistoryVisibility()); btnToggleHistory.setOnClickListener(v -> toggleHistoryVisibility());
} }
// --- FIKS FOR NULLPOINTER EXCEPTION LAYOUTTRANSITION ---
if (view instanceof ViewGroup) { if (view instanceof ViewGroup) {
LayoutTransition transition = ((ViewGroup) view).getLayoutTransition(); LayoutTransition transition = ((ViewGroup) view).getLayoutTransition();
if (transition == null) { if (transition == null) {
@ -198,7 +205,6 @@ public class FormsFragment extends Fragment {
} }
transition.enableTransitionType(LayoutTransition.CHANGING); transition.enableTransitionType(LayoutTransition.CHANGING);
} }
// ----------------------------------------------------------
if (formContainer == null) { if (formContainer == null) {
formContainer = new LinearLayout(getContext()); formContainer = new LinearLayout(getContext());
@ -229,11 +235,9 @@ public class FormsFragment extends Fragment {
if (historyWrapper == null || btnToggleHistory == null) return; if (historyWrapper == null || btnToggleHistory == null) return;
if (historyWrapper.getVisibility() == View.VISIBLE) { if (historyWrapper.getVisibility() == View.VISIBLE) {
// Skjul historikk
historyWrapper.setVisibility(View.GONE); historyWrapper.setVisibility(View.GONE);
btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float); btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
} else { } else {
// Vis historikk
historyWrapper.setVisibility(View.VISIBLE); historyWrapper.setVisibility(View.VISIBLE);
btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float); btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
} }
@ -300,20 +304,17 @@ public class FormsFragment extends Fragment {
nestedEntries.clear(); nestedEntries.clear();
updateStatus(""); updateStatus("");
// Reset visibility of history on new load // NYTT: Sett tittelen i Toolbaren i stedet for å legge til en TextView
if (toolbar != null) {
toolbar.setTitle(getCleanTitle(form.title));
}
if (historyWrapper != null) { if (historyWrapper != null) {
historyWrapper.setVisibility(View.VISIBLE); historyWrapper.setVisibility(View.VISIBLE);
if (btnToggleHistory != null) btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float); if (btnToggleHistory != null) btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
} }
TextView title = new TextView(getContext()); // Beskrivelse legges fortsatt inn som innhold
title.setText(getCleanTitle(form.title));
title.setTextSize(24);
title.setTypeface(null, Typeface.BOLD);
title.setTextColor(Color.BLACK);
title.setPadding(0, 0, 0, 20);
formContainer.addView(title);
if (form.description != null && !form.description.isEmpty()) { if (form.description != null && !form.description.isEmpty()) {
TextView formDesc = new TextView(getContext()); TextView formDesc = new TextView(getContext());
String cleanDesc = form.description.replaceFirst("^\\d+\\.\\s*", ""); String cleanDesc = form.description.replaceFirst("^\\d+\\.\\s*", "");
@ -429,14 +430,13 @@ public class FormsFragment extends Fragment {
btnAdd.setBackgroundColor(Color.parseColor("#53AFE9")); btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
btnAdd.setTextColor(Color.WHITE); btnAdd.setTextColor(Color.WHITE);
btnAdd.setOnClickListener(v -> { btnAdd.setOnClickListener(v -> {
expandFormModule(); // Trigger expand expandFormModule();
int childFormId = 18; int childFormId = 18;
if (field.gpnfForm != null) { if (field.gpnfForm != null) {
try { try {
childFormId = Integer.parseInt(field.gpnfForm); childFormId = Integer.parseInt(field.gpnfForm);
} catch (NumberFormatException e) { e.printStackTrace(); } } catch (NumberFormatException e) { e.printStackTrace(); }
} }
// NYTT: Sender med felt-ID fra hovedskjemaet (f.eks "25")
openChildFormDialog(childFormId, field.id); openChildFormDialog(childFormId, field.id);
}); });
container.addView(btnAdd); container.addView(btnAdd);
@ -455,7 +455,6 @@ public class FormsFragment extends Fragment {
container.addView(totalAmountView); container.addView(totalAmountView);
} }
// NY SIGNATUR: Tar imot parentFieldId
private void openChildFormDialog(int childFormId, String parentFieldId) { private void openChildFormDialog(int childFormId, String parentFieldId) {
if (getActivity() == null) return; if (getActivity() == null) return;
ProgressBar pBar = new ProgressBar(getContext()); ProgressBar pBar = new ProgressBar(getContext());
@ -483,7 +482,6 @@ public class FormsFragment extends Fragment {
}); });
} }
// NY SIGNATUR: Tar imot parentFieldId
private void showChildFormDialog(GravityForm childForm, String parentFieldId) { private void showChildFormDialog(GravityForm childForm, String parentFieldId) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
childInputViews.clear(); childInputViews.clear();
@ -533,7 +531,6 @@ public class FormsFragment extends Fragment {
}); });
} }
// NY SIGNATUR: Tar imot parentFieldId og sender den som meta
private void submitChildForm(int childFormId, AlertDialog dialog, String parentFieldId) { private void submitChildForm(int childFormId, AlertDialog dialog, String parentFieldId) {
JSONObject inputValues = new JSONObject(); JSONObject inputValues = new JSONObject();
for (Map.Entry<String, View> entry : childInputViews.entrySet()) { for (Map.Entry<String, View> entry : childInputViews.entrySet()) {
@ -559,13 +556,9 @@ public class FormsFragment extends Fragment {
} }
} }
// --- HER ER FIKSEN FOR BUGGEN ---
// Vi legger ved en ekstra parameter som forteller Gravity Forms at dette
// er en nested entry som hører til et bestemt felt (f.eks "25").
if (parentFieldId != null) { if (parentFieldId != null) {
textParts.put("gpnf_entry_nested_form_field", RequestBody.create(MultipartBody.FORM, parentFieldId)); textParts.put("gpnf_entry_nested_form_field", RequestBody.create(MultipartBody.FORM, parentFieldId));
} }
// ---------------------------------
for (Map.Entry<String, Uri> fileEntry : childFileUploads.entrySet()) { for (Map.Entry<String, Uri> fileEntry : childFileUploads.entrySet()) {
String fieldId = fileEntry.getKey(); String fieldId = fileEntry.getKey();
@ -585,9 +578,6 @@ public class FormsFragment extends Fragment {
JsonObject json = response.body().getAsJsonObject(); JsonObject json = response.body().getAsJsonObject();
if (json.has("is_valid") && json.get("is_valid").getAsBoolean()) { if (json.has("is_valid") && json.get("is_valid").getAsBoolean()) {
String entryId = json.has("entry_id") ? json.get("entry_id").getAsString() : ""; String entryId = json.has("entry_id") ? json.get("entry_id").getAsString() : "";
// NB: Tilpass ID-ene her hvis skjema 18 endres.
// ID 3 = Beskrivelse, ID 4 = Beløp
String desc = getInputValueGeneric(childInputViews.get("3")); String desc = getInputValueGeneric(childInputViews.get("3"));
String price = getInputValueGeneric(childInputViews.get("4")); String price = getInputValueGeneric(childInputViews.get("4"));
addNestedEntry(entryId, desc, price); addNestedEntry(entryId, desc, price);
@ -661,10 +651,9 @@ public class FormsFragment extends Fragment {
Button btnUpload = new Button(getContext()); Button btnUpload = new Button(getContext());
btnUpload.setText("Velg fil / Ta bilde"); btnUpload.setText("Velg fil / Ta bilde");
btnUpload.setOnClickListener(v -> { btnUpload.setOnClickListener(v -> {
// Setter state før vi viser dialog
pendingFileFieldId = field.id; pendingFileFieldId = field.id;
isSelectingForChild = isChild; isSelectingForChild = isChild;
expandFormModule(); // Trigger expand expandFormModule();
showFileSourceDialog(); showFileSourceDialog();
}); });
TextView txtFileName = new TextView(getContext()); TextView txtFileName = new TextView(getContext());
@ -681,23 +670,19 @@ public class FormsFragment extends Fragment {
reqMap.put(field.id, field.isRequired); reqMap.put(field.id, field.isRequired);
} }
// Hjelpemetode for å vise dialog
private void showFileSourceDialog() { private void showFileSourceDialog() {
String[] options = {"Ta bilde", "Velg fil"}; String[] options = {"Ta bilde", "Velg fil"};
new AlertDialog.Builder(getContext()) new AlertDialog.Builder(getContext())
.setTitle("Last opp vedlegg") .setTitle("Last opp vedlegg")
.setItems(options, (dialog, which) -> { .setItems(options, (dialog, which) -> {
if (which == 0) { if (which == 0) {
// Ta bilde - SJEKKER PERMISSION FØRST
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) { == PackageManager.PERMISSION_GRANTED) {
openCamera(); openCamera();
} else { } else {
// Spør om lov
requestPermissionLauncher.launch(Manifest.permission.CAMERA); requestPermissionLauncher.launch(Manifest.permission.CAMERA);
} }
} else { } else {
// Velg fil
if (filePickerLauncher != null) { if (filePickerLauncher != null) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT); Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*"); intent.setType("*/*");
@ -790,7 +775,7 @@ public class FormsFragment extends Fragment {
timeInput.setClickable(true); timeInput.setClickable(true);
timeInput.setHint("00:00"); timeInput.setHint("00:00");
timeInput.setOnClickListener(v -> { timeInput.setOnClickListener(v -> {
expandFormModule(); // Trigger expand expandFormModule();
Calendar mcurrentTime = Calendar.getInstance(); Calendar mcurrentTime = Calendar.getInstance();
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY); int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
int minute = mcurrentTime.get(Calendar.MINUTE); int minute = mcurrentTime.get(Calendar.MINUTE);
@ -831,7 +816,7 @@ public class FormsFragment extends Fragment {
public void onTextChanged(CharSequence s, int start, int before, int count) {} public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); } public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
}); });
attachInteractionListener(input); // Add listener attachInteractionListener(input);
container.addView(input); container.addView(input);
views.put(field.id, input); views.put(field.id, input);
@ -845,7 +830,7 @@ public class FormsFragment extends Fragment {
input.setMinLines(3); input.setMinLines(3);
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START); input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
attachInteractionListener(input); // Add listener attachInteractionListener(input);
container.addView(input); container.addView(input);
views.put(field.id, input); views.put(field.id, input);
@ -859,7 +844,6 @@ public class FormsFragment extends Fragment {
RadioButton rb = new RadioButton(getContext()); RadioButton rb = new RadioButton(getContext());
rb.setText(choice.text); rb.setText(choice.text);
rb.setTag(choice.value); rb.setTag(choice.value);
// Also trigger expand on RadioButton click
rb.setOnClickListener(v -> { rb.setOnClickListener(v -> {
expandFormModule(); expandFormModule();
evaluateAllConditionalLogic(); evaluateAllConditionalLogic();
@ -867,7 +851,6 @@ public class FormsFragment extends Fragment {
group.addView(rb); group.addView(rb);
} }
} }
// Fallback listener
group.setOnCheckedChangeListener((g, i) -> { group.setOnCheckedChangeListener((g, i) -> {
expandFormModule(); expandFormModule();
evaluateAllConditionalLogic(); evaluateAllConditionalLogic();
@ -879,7 +862,6 @@ public class FormsFragment extends Fragment {
private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) { private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
Spinner spinner = new Spinner(getContext()); Spinner spinner = new Spinner(getContext());
// Spinner touch listener is tricky, usually set onTouchListener works
spinner.setOnTouchListener((v, event) -> { spinner.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getAction() == MotionEvent.ACTION_DOWN) {
expandFormModule(); expandFormModule();
@ -922,7 +904,6 @@ public class FormsFragment extends Fragment {
checkBox.setText(inputDef.label); checkBox.setText(inputDef.label);
String value = "1"; String value = "1";
// Fallback
if (field.choices != null && i < field.choices.size()) { if (field.choices != null && i < field.choices.size()) {
value = field.choices.get(i).value; value = field.choices.get(i).value;
} }
@ -940,24 +921,20 @@ public class FormsFragment extends Fragment {
private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) { private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
EditText dateInput = new EditText(getContext()); EditText dateInput = new EditText(getContext());
// --- DATO LØSNING (Fix for Read Only / Dagens Dato) ---
if (field.readOnly || (formId == ID_REFUSJON_UTLEGG && "28".equals(field.id))) { if (field.readOnly || (formId == ID_REFUSJON_UTLEGG && "28".equals(field.id))) {
// Sett dagens dato
SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()); SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
dateInput.setText(df.format(new Date())); dateInput.setText(df.format(new Date()));
// Gjør den "read-only" men synlig
dateInput.setFocusable(false); dateInput.setFocusable(false);
dateInput.setClickable(false); dateInput.setClickable(false);
dateInput.setEnabled(false); dateInput.setEnabled(false);
dateInput.setTextColor(Color.BLACK); dateInput.setTextColor(Color.BLACK);
} else { } else {
// Vanlig dato-velger
dateInput.setFocusable(false); dateInput.setFocusable(false);
dateInput.setClickable(true); dateInput.setClickable(true);
dateInput.setHint("dd.mm.yyyy"); dateInput.setHint("dd.mm.yyyy");
dateInput.setOnClickListener(v -> { dateInput.setOnClickListener(v -> {
expandFormModule(); // Trigger expand expandFormModule();
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> { new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year)); dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
@ -1361,20 +1338,17 @@ public class FormsFragment extends Fragment {
} }
try { try {
// Vis flere oppføringer siden vi har scrolle-mulighet øverst
int count = Math.min(entries.length(), 20); int count = Math.min(entries.length(), 20);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
JSONObject entry = entries.getJSONObject(i); JSONObject entry = entries.getJSONObject(i);
String date = entry.optString("date_created"); String date = entry.optString("date_created");
// Prøv å finne en bedre tittel enn bare dato (f.eks Prosjektnavn eller Sted)
String titleText = "Innsendt: " + date; String titleText = "Innsendt: " + date;
TextView item = new TextView(getContext()); TextView item = new TextView(getContext());
item.setText(titleText); item.setText(titleText);
item.setPadding(10, 20, 10, 20); item.setPadding(10, 20, 10, 20);
item.setBackgroundResource(android.R.drawable.list_selector_background); item.setBackgroundResource(android.R.drawable.list_selector_background);
item.setTextSize(14); item.setTextSize(14);
// Add click listener to show details
item.setOnClickListener(v -> showEntryDetails(entry)); item.setOnClickListener(v -> showEntryDetails(entry));
View line = new View(getContext()); View line = new View(getContext());
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
@ -1387,20 +1361,16 @@ public class FormsFragment extends Fragment {
} }
} }
// NY METODE: Vis detaljer i dialog med delingsknapp
private void showEntryDetails(JSONObject entry) { private void showEntryDetails(JSONObject entry) {
// HVIS dette er Form 16 (Refusjon), vi først hente vedleggene (som ligger i Form 18)
if (formId == ID_REFUSJON_UTLEGG) { if (formId == ID_REFUSJON_UTLEGG) {
Log.d(TAG, "Form 16 detected. Checking for child entries..."); Log.d(TAG, "Form 16 detected. Checking for child entries...");
String nestedIds = entry.optString("25"); // Felt 25 i Form 16 inneholder ID-ene til vedleggene String nestedIds = entry.optString("25");
if (!nestedIds.isEmpty()) { if (!nestedIds.isEmpty()) {
Log.d(TAG, "Nested IDs found: " + nestedIds); Log.d(TAG, "Nested IDs found: " + nestedIds);
List<String> ids = new ArrayList<>(); List<String> ids = new ArrayList<>();
// ROBUST PARSING AV ID-LISTE
if (nestedIds.startsWith("[") && nestedIds.endsWith("]")) { if (nestedIds.startsWith("[") && nestedIds.endsWith("]")) {
// Dette er en JSON-array streng (f.eks [101, 102])
try { try {
JSONArray jsonArray = new JSONArray(nestedIds); JSONArray jsonArray = new JSONArray(nestedIds);
for(int i=0; i<jsonArray.length(); i++) { for(int i=0; i<jsonArray.length(); i++) {
@ -1410,42 +1380,34 @@ public class FormsFragment extends Fragment {
Log.e(TAG, "Failed to parse nested IDs as JSON array", e); Log.e(TAG, "Failed to parse nested IDs as JSON array", e);
} }
} else { } else {
// Dette er en komma-separert streng (f.eks "101, 102")
for (String id : nestedIds.split(",")) { for (String id : nestedIds.split(",")) {
ids.add(id.trim()); ids.add(id.trim());
} }
} }
if (!ids.isEmpty()) { if (!ids.isEmpty()) {
// Vis en "Laster..." dialog mens vi henter data
AlertDialog loadingDialog = new AlertDialog.Builder(getContext()) AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
.setMessage("Henter vedleggsdetaljer...") .setMessage("Henter vedleggsdetaljer...")
.setCancelable(false) .setCancelable(false)
.show(); .show();
// Start rekursiv henting
StringBuilder accumulatedHtml = new StringBuilder(); StringBuilder accumulatedHtml = new StringBuilder();
StringBuilder accumulatedText = new StringBuilder(); StringBuilder accumulatedText = new StringBuilder();
// Legg først til basis-info fra hovedskjemaet
appendBasicInfo(entry, accumulatedHtml, accumulatedText); appendBasicInfo(entry, accumulatedHtml, accumulatedText);
fetchChildEntriesRecursive(ids, 0, accumulatedHtml, accumulatedText, loadingDialog); fetchChildEntriesRecursive(ids, 0, accumulatedHtml, accumulatedText, loadingDialog);
return; // Stopp her, dialogen vises når data er hentet return;
} }
} else {
Log.d(TAG, "No nested IDs found in field 25.");
} }
} }
// --- STANDARD VISNING (For alle andre skjemaer) ---
StringBuilder htmlBuilder = new StringBuilder(); StringBuilder htmlBuilder = new StringBuilder();
StringBuilder textBuilder = new StringBuilder(); StringBuilder textBuilder = new StringBuilder();
appendBasicInfo(entry, htmlBuilder, textBuilder); appendBasicInfo(entry, htmlBuilder, textBuilder);
showFinalDialog(htmlBuilder, textBuilder); showFinalDialog(htmlBuilder, textBuilder);
} }
// Hjelpemetode for å legge til info fra hovedskjemaet
private void appendBasicInfo(JSONObject entry, StringBuilder html, StringBuilder text) { private void appendBasicInfo(JSONObject entry, StringBuilder html, StringBuilder text) {
try { try {
String date = entry.optString("date_created"); String date = entry.optString("date_created");
@ -1455,7 +1417,6 @@ public class FormsFragment extends Fragment {
if (currentForm != null && currentForm.fields != null) { if (currentForm != null && currentForm.fields != null) {
for (GravityField field : currentForm.fields) { for (GravityField field : currentForm.fields) {
if ("section".equals(field.type) || "html".equals(field.type) || "captcha".equals(field.type)) continue; if ("section".equals(field.type) || "html".equals(field.type) || "captcha".equals(field.type)) continue;
// Hopp over felt 25 (Vedleggs-IDer) i Form 16, siden vi viser det bedre senere
if (formId == ID_REFUSJON_UTLEGG && "25".equals(field.id)) continue; if (formId == ID_REFUSJON_UTLEGG && "25".equals(field.id)) continue;
String value = ""; String value = "";
@ -1470,8 +1431,6 @@ public class FormsFragment extends Fragment {
if (!value.trim().isEmpty()) { if (!value.trim().isEmpty()) {
if ("fileupload".equals(field.type)) { if ("fileupload".equals(field.type)) {
// Håndter filopplastinger (single/multiple)
// Her antar vi enkel URL, men for sikkerhets skyld bruker vi extractUrl
String cleanUrl = extractUrl(value); String cleanUrl = extractUrl(value);
if (cleanUrl.startsWith("http")) { if (cleanUrl.startsWith("http")) {
html.append("<b>").append(field.label).append(":</b><br>") html.append("<b>").append(field.label).append(":</b><br>")
@ -1491,27 +1450,20 @@ public class FormsFragment extends Fragment {
} catch (Exception e) {} } catch (Exception e) {}
} }
// Rekursiv metode for å hente barn-oppføringer (Vedlegg)
private void fetchChildEntriesRecursive(List<String> ids, int index, StringBuilder html, StringBuilder text, AlertDialog loader) { private void fetchChildEntriesRecursive(List<String> ids, int index, StringBuilder html, StringBuilder text, AlertDialog loader) {
if (index >= ids.size()) { if (index >= ids.size()) {
// Alle ferdige! Vis dialogen.
loader.dismiss(); loader.dismiss();
showFinalDialog(html, text); showFinalDialog(html, text);
return; return;
} }
String entryId = ids.get(index); String entryId = ids.get(index);
Log.d(TAG, "Fetching child entry ID: " + entryId);
RetrofitClient.getApiService().getSingleEntry(entryId).enqueue(new retrofit2.Callback<JsonElement>() { RetrofitClient.getApiService().getSingleEntry(entryId).enqueue(new retrofit2.Callback<JsonElement>() {
@Override @Override
public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) { public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
try { try {
JsonObject json = response.body().getAsJsonObject(); JsonObject json = response.body().getAsJsonObject();
// I Form 18: Felt 1 = Fil, Felt 3 = Beskrivelse, Felt 4 = Beløp
// Parse Description and Price
String desc = json.has("3") ? json.get("3").getAsString() : "Uten beskrivelse"; String desc = json.has("3") ? json.get("3").getAsString() : "Uten beskrivelse";
String price = json.has("4") ? json.get("4").getAsString() : ""; String price = json.has("4") ? json.get("4").getAsString() : "";
@ -1521,11 +1473,9 @@ public class FormsFragment extends Fragment {
html.append(desc).append(" (").append(price).append(")<br>"); html.append(desc).append(" (").append(price).append(")<br>");
text.append(desc).append(" (").append(price).append(")\n"); text.append(desc).append(" (").append(price).append(")\n");
// Parse File Field (ID 1) - Can be multiple files!
if (json.has("1")) { if (json.has("1")) {
JsonElement fileEl = json.get("1"); JsonElement fileEl = json.get("1");
if (fileEl.isJsonArray()) { if (fileEl.isJsonArray()) {
// It is a real JSON array
JsonArray arr = fileEl.getAsJsonArray(); JsonArray arr = fileEl.getAsJsonArray();
for (int i = 0; i < arr.size(); i++) { for (int i = 0; i < arr.size(); i++) {
String url = arr.get(i).getAsString().replace("\\/", "/"); String url = arr.get(i).getAsString().replace("\\/", "/");
@ -1533,7 +1483,6 @@ public class FormsFragment extends Fragment {
text.append(url).append("\n"); text.append(url).append("\n");
} }
} else { } else {
// It is a string. Check if it's a JSON string array like "[\"http...\"]"
String rawString = fileEl.getAsString(); String rawString = fileEl.getAsString();
if (rawString.startsWith("[") && rawString.endsWith("]")) { if (rawString.startsWith("[") && rawString.endsWith("]")) {
try { try {
@ -1544,13 +1493,11 @@ public class FormsFragment extends Fragment {
text.append(url).append("\n"); text.append(url).append("\n");
} }
} catch (JSONException ex) { } catch (JSONException ex) {
// Fallback: simple cleanup
String clean = extractUrl(rawString); String clean = extractUrl(rawString);
html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>"); html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
text.append(clean).append("\n"); text.append(clean).append("\n");
} }
} else { } else {
// Just a plain URL string
String clean = extractUrl(rawString); String clean = extractUrl(rawString);
if(clean.startsWith("http")) { if(clean.startsWith("http")) {
html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>"); html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
@ -1565,17 +1512,12 @@ public class FormsFragment extends Fragment {
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error parsing child entry", e); Log.e(TAG, "Error parsing child entry", e);
} }
} else {
Log.e(TAG, "Failed to fetch child entry: " + response.code());
} }
// til neste (uansett om denne feilet eller ei)
fetchChildEntriesRecursive(ids, index + 1, html, text, loader); fetchChildEntriesRecursive(ids, index + 1, html, text, loader);
} }
@Override @Override
public void onFailure(retrofit2.Call<JsonElement> call, Throwable t) { public void onFailure(retrofit2.Call<JsonElement> call, Throwable t) {
Log.e(TAG, "Network error fetching child entry", t);
// Hopp over ved feil
fetchChildEntriesRecursive(ids, index + 1, html, text, loader); fetchChildEntriesRecursive(ids, index + 1, html, text, loader);
} }
}); });
@ -1598,7 +1540,6 @@ public class FormsFragment extends Fragment {
.show(); .show();
} }
// Hjelpemetode for å rydde opp i URLer fra JSON (f.eks ["http://..."] -> http://...)
private String extractUrl(String rawValue) { private String extractUrl(String rawValue) {
if (rawValue == null) return ""; if (rawValue == null) return "";
String clean = rawValue.replace("[", "") String clean = rawValue.replace("[", "")

View file

@ -8,6 +8,25 @@
android:background="#F5F5F5" android:background="#F5F5F5"
tools:context=".FormsFragment"> tools:context=".FormsFragment">
<!-- NYTT: Toolbar med tilbake-knapp -->
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Light">
<androidx.appcompat.widget.Toolbar
android:id="@+id/forms_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/white"
app:navigationIcon="@android:drawable/ic_menu_revert"
app:titleTextColor="@color/black"
app:title="Laster..." />
</com.google.android.material.appbar.AppBarLayout>
<!-- Resten er likt, men nå under toolbaren -->
<LinearLayout <LinearLayout
android:id="@+id/history_wrapper" android:id="@+id/history_wrapper"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -2,6 +2,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@android:color/white"> android:background="@android:color/white">
@ -91,12 +92,17 @@
android:text="Av: Forfatter"/> android:text="Av: Forfatter"/>
</LinearLayout> </LinearLayout>
<!-- BYTTET FRA TextView TIL WebView --> <!--
WebView for innhold.
tools:ignore="WebViewLayout" hindrer feilmeldingen om wrap_content,
da dette er ønsket oppførsel inne i en NestedScrollView.
-->
<WebView <WebView
android:id="@+id/detail_webview" android:id="@+id/detail_webview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scrollbars="none" /> android:scrollbars="none"
tools:ignore="WebViewLayout" />
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>