diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..35c0201 --- /dev/null +++ b/app/google-services.json @@ -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" +} \ No newline at end of file diff --git a/app/src/main/java/com/kbs/kbsintranett/FormsFragment.java b/app/src/main/java/com/kbs/kbsintranett/FormsFragment.java index 3692db6..fcf4796 100644 --- a/app/src/main/java/com/kbs/kbsintranett/FormsFragment.java +++ b/app/src/main/java/com/kbs/kbsintranett/FormsFragment.java @@ -43,14 +43,15 @@ import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.fragment.app.Fragment; +import androidx.navigation.Navigation; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonArray; -import com.google.gson.JsonParser; import org.json.JSONArray; import org.json.JSONException; @@ -102,11 +103,12 @@ public class FormsFragment extends Fragment { private LinearLayout formContainer; private LinearLayout historyContainer; - private View historyWrapper; // Wrapper for historikk-modulen + private View historyWrapper; private TextView txtStatus; private TextView lblHistory; private ProgressBar loadingSpinner; private ImageView btnToggleHistory; + private Toolbar toolbar; // NYTT // --- HOVEDSKJEMA STATE --- private Map fieldWrappers = new HashMap<>(); @@ -118,7 +120,7 @@ public class FormsFragment extends Fragment { private Map childInputViews = new HashMap<>(); private Map childRequiredFieldsMap = new HashMap<>(); private Map childFileUploads = new HashMap<>(); - // Lagring av Nested Entries + private List nestedEntries = new ArrayList<>(); private LinearLayout nestedEntriesContainer; private TextView totalAmountView; @@ -184,12 +186,17 @@ public class FormsFragment extends Fragment { lblHistory = view.findViewById(R.id.lbl_history); 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); if (btnToggleHistory != null) { btnToggleHistory.setOnClickListener(v -> toggleHistoryVisibility()); } - // --- FIKS FOR NULLPOINTER EXCEPTION PÅ LAYOUTTRANSITION --- if (view instanceof ViewGroup) { LayoutTransition transition = ((ViewGroup) view).getLayoutTransition(); if (transition == null) { @@ -198,7 +205,6 @@ public class FormsFragment extends Fragment { } transition.enableTransitionType(LayoutTransition.CHANGING); } - // ---------------------------------------------------------- if (formContainer == null) { formContainer = new LinearLayout(getContext()); @@ -229,11 +235,9 @@ public class FormsFragment extends Fragment { if (historyWrapper == null || btnToggleHistory == null) return; if (historyWrapper.getVisibility() == View.VISIBLE) { - // Skjul historikk historyWrapper.setVisibility(View.GONE); btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float); } else { - // Vis historikk historyWrapper.setVisibility(View.VISIBLE); btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float); } @@ -300,20 +304,17 @@ public class FormsFragment extends Fragment { nestedEntries.clear(); 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) { historyWrapper.setVisibility(View.VISIBLE); if (btnToggleHistory != null) btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float); } - TextView title = new TextView(getContext()); - 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); - + // Beskrivelse legges fortsatt inn som innhold if (form.description != null && !form.description.isEmpty()) { TextView formDesc = new TextView(getContext()); String cleanDesc = form.description.replaceFirst("^\\d+\\.\\s*", ""); @@ -429,14 +430,13 @@ public class FormsFragment extends Fragment { btnAdd.setBackgroundColor(Color.parseColor("#53AFE9")); btnAdd.setTextColor(Color.WHITE); btnAdd.setOnClickListener(v -> { - expandFormModule(); // Trigger expand + expandFormModule(); int childFormId = 18; if (field.gpnfForm != null) { try { childFormId = Integer.parseInt(field.gpnfForm); } catch (NumberFormatException e) { e.printStackTrace(); } } - // NYTT: Sender med felt-ID fra hovedskjemaet (f.eks "25") openChildFormDialog(childFormId, field.id); }); container.addView(btnAdd); @@ -455,7 +455,6 @@ public class FormsFragment extends Fragment { container.addView(totalAmountView); } - // NY SIGNATUR: Tar imot parentFieldId private void openChildFormDialog(int childFormId, String parentFieldId) { if (getActivity() == null) return; 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) { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 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) { JSONObject inputValues = new JSONObject(); for (Map.Entry 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) { textParts.put("gpnf_entry_nested_form_field", RequestBody.create(MultipartBody.FORM, parentFieldId)); } - // --------------------------------- for (Map.Entry fileEntry : childFileUploads.entrySet()) { String fieldId = fileEntry.getKey(); @@ -585,9 +578,6 @@ public class FormsFragment extends Fragment { JsonObject json = response.body().getAsJsonObject(); if (json.has("is_valid") && json.get("is_valid").getAsBoolean()) { 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 price = getInputValueGeneric(childInputViews.get("4")); addNestedEntry(entryId, desc, price); @@ -661,10 +651,9 @@ public class FormsFragment extends Fragment { Button btnUpload = new Button(getContext()); btnUpload.setText("Velg fil / Ta bilde"); btnUpload.setOnClickListener(v -> { - // Setter state før vi viser dialog pendingFileFieldId = field.id; isSelectingForChild = isChild; - expandFormModule(); // Trigger expand + expandFormModule(); showFileSourceDialog(); }); TextView txtFileName = new TextView(getContext()); @@ -681,23 +670,19 @@ public class FormsFragment extends Fragment { reqMap.put(field.id, field.isRequired); } - // Hjelpemetode for å vise dialog private void showFileSourceDialog() { String[] options = {"Ta bilde", "Velg fil"}; new AlertDialog.Builder(getContext()) .setTitle("Last opp vedlegg") .setItems(options, (dialog, which) -> { if (which == 0) { - // Ta bilde - SJEKKER PERMISSION FØRST if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { openCamera(); } else { - // Spør om lov requestPermissionLauncher.launch(Manifest.permission.CAMERA); } } else { - // Velg fil if (filePickerLauncher != null) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); @@ -790,7 +775,7 @@ public class FormsFragment extends Fragment { timeInput.setClickable(true); timeInput.setHint("00:00"); timeInput.setOnClickListener(v -> { - expandFormModule(); // Trigger expand + expandFormModule(); Calendar mcurrentTime = Calendar.getInstance(); int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY); 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 afterTextChanged(Editable s) { evaluateAllConditionalLogic(); } }); - attachInteractionListener(input); // Add listener + attachInteractionListener(input); container.addView(input); views.put(field.id, input); @@ -845,7 +830,7 @@ public class FormsFragment extends Fragment { input.setMinLines(3); input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START); - attachInteractionListener(input); // Add listener + attachInteractionListener(input); container.addView(input); views.put(field.id, input); @@ -859,7 +844,6 @@ public class FormsFragment extends Fragment { RadioButton rb = new RadioButton(getContext()); rb.setText(choice.text); rb.setTag(choice.value); - // Also trigger expand on RadioButton click rb.setOnClickListener(v -> { expandFormModule(); evaluateAllConditionalLogic(); @@ -867,7 +851,6 @@ public class FormsFragment extends Fragment { group.addView(rb); } } - // Fallback listener group.setOnCheckedChangeListener((g, i) -> { expandFormModule(); evaluateAllConditionalLogic(); @@ -879,7 +862,6 @@ public class FormsFragment extends Fragment { private void renderSelectField(LinearLayout container, GravityField field, Map views, Map req) { Spinner spinner = new Spinner(getContext()); - // Spinner touch listener is tricky, usually set onTouchListener works spinner.setOnTouchListener((v, event) -> { if (event.getAction() == MotionEvent.ACTION_DOWN) { expandFormModule(); @@ -922,7 +904,6 @@ public class FormsFragment extends Fragment { checkBox.setText(inputDef.label); String value = "1"; - // Fallback if (field.choices != null && i < field.choices.size()) { value = field.choices.get(i).value; } @@ -940,24 +921,20 @@ public class FormsFragment extends Fragment { private void renderDateField(LinearLayout container, GravityField field, Map views, Map req) { 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))) { - // Sett dagens dato SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()); dateInput.setText(df.format(new Date())); - // Gjør den "read-only" men synlig dateInput.setFocusable(false); dateInput.setClickable(false); dateInput.setEnabled(false); dateInput.setTextColor(Color.BLACK); } else { - // Vanlig dato-velger dateInput.setFocusable(false); dateInput.setClickable(true); dateInput.setHint("dd.mm.yyyy"); dateInput.setOnClickListener(v -> { - expandFormModule(); // Trigger expand + expandFormModule(); Calendar c = Calendar.getInstance(); new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> { dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year)); @@ -1361,20 +1338,17 @@ public class FormsFragment extends Fragment { } try { - // Vis flere oppføringer siden vi nå har scrolle-mulighet øverst int count = Math.min(entries.length(), 20); for (int i = 0; i < count; i++) { JSONObject entry = entries.getJSONObject(i); String date = entry.optString("date_created"); - // Prøv å finne en bedre tittel enn bare dato (f.eks Prosjektnavn eller Sted) String titleText = "Innsendt: " + date; TextView item = new TextView(getContext()); item.setText(titleText); item.setPadding(10, 20, 10, 20); item.setBackgroundResource(android.R.drawable.list_selector_background); item.setTextSize(14); - // Add click listener to show details item.setOnClickListener(v -> showEntryDetails(entry)); View line = new View(getContext()); 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) { - // HVIS dette er Form 16 (Refusjon), må vi først hente vedleggene (som ligger i Form 18) if (formId == ID_REFUSJON_UTLEGG) { 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()) { Log.d(TAG, "Nested IDs found: " + nestedIds); List ids = new ArrayList<>(); - // ROBUST PARSING AV ID-LISTE if (nestedIds.startsWith("[") && nestedIds.endsWith("]")) { - // Dette er en JSON-array streng (f.eks [101, 102]) try { JSONArray jsonArray = new JSONArray(nestedIds); for(int i=0; i").append(field.label).append(":
") @@ -1491,27 +1450,20 @@ public class FormsFragment extends Fragment { } catch (Exception e) {} } - // Rekursiv metode for å hente barn-oppføringer (Vedlegg) private void fetchChildEntriesRecursive(List ids, int index, StringBuilder html, StringBuilder text, AlertDialog loader) { if (index >= ids.size()) { - // Alle ferdige! Vis dialogen. loader.dismiss(); showFinalDialog(html, text); return; } String entryId = ids.get(index); - Log.d(TAG, "Fetching child entry ID: " + entryId); - RetrofitClient.getApiService().getSingleEntry(entryId).enqueue(new retrofit2.Callback() { @Override public void onResponse(retrofit2.Call call, retrofit2.Response response) { if (response.isSuccessful() && response.body() != null) { try { 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 price = json.has("4") ? json.get("4").getAsString() : ""; @@ -1521,11 +1473,9 @@ public class FormsFragment extends Fragment { html.append(desc).append(" (").append(price).append(")
"); text.append(desc).append(" (").append(price).append(")\n"); - // Parse File Field (ID 1) - Can be multiple files! if (json.has("1")) { JsonElement fileEl = json.get("1"); if (fileEl.isJsonArray()) { - // It is a real JSON array JsonArray arr = fileEl.getAsJsonArray(); for (int i = 0; i < arr.size(); i++) { String url = arr.get(i).getAsString().replace("\\/", "/"); @@ -1533,7 +1483,6 @@ public class FormsFragment extends Fragment { text.append(url).append("\n"); } } else { - // It is a string. Check if it's a JSON string array like "[\"http...\"]" String rawString = fileEl.getAsString(); if (rawString.startsWith("[") && rawString.endsWith("]")) { try { @@ -1544,13 +1493,11 @@ public class FormsFragment extends Fragment { text.append(url).append("\n"); } } catch (JSONException ex) { - // Fallback: simple cleanup String clean = extractUrl(rawString); html.append("Åpne fil
"); text.append(clean).append("\n"); } } else { - // Just a plain URL string String clean = extractUrl(rawString); if(clean.startsWith("http")) { html.append("Åpne fil
"); @@ -1565,17 +1512,12 @@ public class FormsFragment extends Fragment { } catch (Exception e) { Log.e(TAG, "Error parsing child entry", e); } - } else { - Log.e(TAG, "Failed to fetch child entry: " + response.code()); } - // Gå til neste (uansett om denne feilet eller ei) fetchChildEntriesRecursive(ids, index + 1, html, text, loader); } @Override public void onFailure(retrofit2.Call call, Throwable t) { - Log.e(TAG, "Network error fetching child entry", t); - // Hopp over ved feil fetchChildEntriesRecursive(ids, index + 1, html, text, loader); } }); @@ -1598,7 +1540,6 @@ public class FormsFragment extends Fragment { .show(); } - // Hjelpemetode for å rydde opp i URLer fra JSON (f.eks ["http://..."] -> http://...) private String extractUrl(String rawValue) { if (rawValue == null) return ""; String clean = rawValue.replace("[", "") diff --git a/app/src/main/res/layout/fragment_forms.xml b/app/src/main/res/layout/fragment_forms.xml index 0190f49..ef36ff2 100644 --- a/app/src/main/res/layout/fragment_forms.xml +++ b/app/src/main/res/layout/fragment_forms.xml @@ -8,6 +8,25 @@ android:background="#F5F5F5" tools:context=".FormsFragment"> + + + + + + + + + @@ -91,12 +92,17 @@ android:text="Av: Forfatter"/> - + + android:scrollbars="none" + tools:ignore="WebViewLayout" />