Før kalenderarbeid
This commit is contained in:
parent
c23b4ba3d3
commit
0c33b4fc0f
3 changed files with 528 additions and 133 deletions
|
|
@ -49,6 +49,8 @@ import androidx.fragment.app.Fragment;
|
|||
|
||||
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;
|
||||
|
|
@ -71,7 +73,6 @@ import java.util.Map;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
|
@ -105,7 +106,7 @@ public class FormsFragment extends Fragment {
|
|||
private TextView txtStatus;
|
||||
private TextView lblHistory;
|
||||
private ProgressBar loadingSpinner;
|
||||
private ImageView btnToggleHistory; // NY: Knapp for å vise/skjule historikk
|
||||
private ImageView btnToggleHistory;
|
||||
|
||||
// --- HOVEDSKJEMA STATE ---
|
||||
private Map<String, View> fieldWrappers = new HashMap<>();
|
||||
|
|
@ -183,12 +184,10 @@ public class FormsFragment extends Fragment {
|
|||
lblHistory = view.findViewById(R.id.lbl_history);
|
||||
loadingSpinner = view.findViewById(R.id.loading_spinner);
|
||||
|
||||
// --- NY KODE START: Vis/Skjul knapp ---
|
||||
btnToggleHistory = view.findViewById(R.id.btn_toggle_history);
|
||||
if (btnToggleHistory != null) {
|
||||
btnToggleHistory.setOnClickListener(v -> toggleHistoryVisibility());
|
||||
}
|
||||
// --- NY KODE SLUTT ---
|
||||
|
||||
// --- FIKS FOR NULLPOINTER EXCEPTION PÅ LAYOUTTRANSITION ---
|
||||
if (view instanceof ViewGroup) {
|
||||
|
|
@ -217,28 +216,24 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
// --- UI LOGIKK FOR DELT SKJERM ---
|
||||
|
||||
// Kalles når brukeren interagerer med et felt i skjemaet
|
||||
private void expandFormModule() {
|
||||
if (historyWrapper != null && historyWrapper.getVisibility() == View.VISIBLE) {
|
||||
historyWrapper.setVisibility(View.GONE);
|
||||
|
||||
// Oppdater ikonet til å peke NED (for å vise at man kan hente historikk ned igjen)
|
||||
if (btnToggleHistory != null) {
|
||||
btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NY METODE: Håndterer klikk på pil-knappen
|
||||
private void toggleHistoryVisibility() {
|
||||
if (historyWrapper == null || btnToggleHistory == null) return;
|
||||
|
||||
if (historyWrapper.getVisibility() == View.VISIBLE) {
|
||||
// Skjul historikk (Gå til fullskjerm)
|
||||
// Skjul historikk
|
||||
historyWrapper.setVisibility(View.GONE);
|
||||
btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
|
||||
} else {
|
||||
// Vis historikk (Gå til splitscreen)
|
||||
// Vis historikk
|
||||
historyWrapper.setVisibility(View.VISIBLE);
|
||||
btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
|
||||
}
|
||||
|
|
@ -246,20 +241,17 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private void attachInteractionListener(View view) {
|
||||
if (view == null) return;
|
||||
// Touch listener fanger opp klikk før tastaturet kommer opp
|
||||
view.setOnTouchListener((v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
expandFormModule();
|
||||
}
|
||||
return false; // Return false to allow normal processing
|
||||
return false;
|
||||
});
|
||||
// Focus listener for edittexts etc
|
||||
view.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
expandFormModule();
|
||||
}
|
||||
});
|
||||
// Click listener for buttons/checkboxes
|
||||
if (view.isClickable()) {
|
||||
view.setOnClickListener(v -> expandFormModule());
|
||||
}
|
||||
|
|
@ -308,7 +300,7 @@ public class FormsFragment extends Fragment {
|
|||
nestedEntries.clear();
|
||||
updateStatus("");
|
||||
|
||||
// Reset visibility of history on new load (Splitscreen start)
|
||||
// Reset visibility of history on new load
|
||||
if (historyWrapper != null) {
|
||||
historyWrapper.setVisibility(View.VISIBLE);
|
||||
if (btnToggleHistory != null) btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
|
||||
|
|
@ -444,7 +436,8 @@ public class FormsFragment extends Fragment {
|
|||
childFormId = Integer.parseInt(field.gpnfForm);
|
||||
} catch (NumberFormatException e) { e.printStackTrace(); }
|
||||
}
|
||||
openChildFormDialog(childFormId);
|
||||
// NYTT: Sender med felt-ID fra hovedskjemaet (f.eks "25")
|
||||
openChildFormDialog(childFormId, field.id);
|
||||
});
|
||||
container.addView(btnAdd);
|
||||
|
||||
|
|
@ -462,7 +455,8 @@ public class FormsFragment extends Fragment {
|
|||
container.addView(totalAmountView);
|
||||
}
|
||||
|
||||
private void openChildFormDialog(int childFormId) {
|
||||
// NY SIGNATUR: Tar imot parentFieldId
|
||||
private void openChildFormDialog(int childFormId, String parentFieldId) {
|
||||
if (getActivity() == null) return;
|
||||
ProgressBar pBar = new ProgressBar(getContext());
|
||||
AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
|
||||
|
|
@ -475,7 +469,7 @@ public class FormsFragment extends Fragment {
|
|||
public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
|
||||
loadingDialog.dismiss();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
showChildFormDialog(response.body());
|
||||
showChildFormDialog(response.body(), parentFieldId);
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Kunne ikke hente underskjema", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
|
@ -489,7 +483,8 @@ public class FormsFragment extends Fragment {
|
|||
});
|
||||
}
|
||||
|
||||
private void showChildFormDialog(GravityForm childForm) {
|
||||
// NY SIGNATUR: Tar imot parentFieldId
|
||||
private void showChildFormDialog(GravityForm childForm, String parentFieldId) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
childInputViews.clear();
|
||||
childRequiredFieldsMap.clear();
|
||||
|
|
@ -534,11 +529,12 @@ public class FormsFragment extends Fragment {
|
|||
dialog.show();
|
||||
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
|
||||
submitChildForm(childForm.id, dialog);
|
||||
submitChildForm(childForm.id, dialog, parentFieldId);
|
||||
});
|
||||
}
|
||||
|
||||
private void submitChildForm(int childFormId, AlertDialog dialog) {
|
||||
// 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<String, View> entry : childInputViews.entrySet()) {
|
||||
String val = getInputValueGeneric(entry.getValue());
|
||||
|
|
@ -562,6 +558,15 @@ public class FormsFragment extends Fragment {
|
|||
textParts.put(key, RequestBody.create(MultipartBody.FORM, val));
|
||||
}
|
||||
}
|
||||
|
||||
// --- 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<String, Uri> fileEntry : childFileUploads.entrySet()) {
|
||||
String fieldId = fileEntry.getKey();
|
||||
Uri uri = fileEntry.getValue();
|
||||
|
|
@ -1196,11 +1201,11 @@ public class FormsFragment extends Fragment {
|
|||
String url = BASE_URL_GF + "/forms/" + formId + "/submissions";
|
||||
Request request = new Request.Builder().url(url).post(body).header("Cookie", cookie).build();
|
||||
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||
public void onFailure(Call call, IOException e) {
|
||||
public void onFailure(okhttp3.Call call, IOException e) {
|
||||
Log.e(TAG, "JSON submit failed", e);
|
||||
updateStatus("Feil: " + e.getMessage());
|
||||
}
|
||||
public void onResponse(Call call, Response response) {
|
||||
public void onResponse(okhttp3.Call call, Response response) {
|
||||
Log.d(TAG, "JSON response code: " + response.code());
|
||||
if (response.isSuccessful()) {
|
||||
if (getActivity() != null) getActivity().runOnUiThread(() -> {
|
||||
|
|
@ -1313,12 +1318,12 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
public void onFailure(@NonNull okhttp3.Call call, @NonNull IOException e) {
|
||||
Log.e(TAG, "Kunne ikke hente historikk", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
public void onResponse(@NonNull okhttp3.Call call, @NonNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
String jsonStr = response.body().string();
|
||||
try {
|
||||
|
|
@ -1382,52 +1387,205 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// NY METODE: Vis detaljer i dialog
|
||||
// NY METODE: Vis detaljer i dialog med delingsknapp
|
||||
private void showEntryDetails(JSONObject entry) {
|
||||
StringBuilder details = new StringBuilder();
|
||||
try {
|
||||
// Loop gjennom alle felter i entry og match med skjema-definisjon
|
||||
// Merk: Entry keys er felt-IDer (f.eks "1", "3.2")
|
||||
// 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
|
||||
|
||||
if (!nestedIds.isEmpty()) {
|
||||
Log.d(TAG, "Nested IDs found: " + nestedIds);
|
||||
List<String> 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<jsonArray.length(); i++) {
|
||||
ids.add(jsonArray.getString(i));
|
||||
}
|
||||
} catch(JSONException e) {
|
||||
Log.e(TAG, "Failed to parse nested IDs as JSON array", e);
|
||||
}
|
||||
} else {
|
||||
// Dette er en komma-separert streng (f.eks "101, 102")
|
||||
for (String id : nestedIds.split(",")) {
|
||||
ids.add(id.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (!ids.isEmpty()) {
|
||||
// Vis en "Laster..." dialog mens vi henter data
|
||||
AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
|
||||
.setMessage("Henter vedleggsdetaljer...")
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
|
||||
// Start rekursiv henting
|
||||
StringBuilder accumulatedHtml = new StringBuilder();
|
||||
StringBuilder accumulatedText = new StringBuilder();
|
||||
|
||||
// Legg først til basis-info fra hovedskjemaet
|
||||
appendBasicInfo(entry, accumulatedHtml, accumulatedText);
|
||||
|
||||
fetchChildEntriesRecursive(ids, 0, accumulatedHtml, accumulatedText, loadingDialog);
|
||||
return; // Stopp her, dialogen vises når data er hentet
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "No nested IDs found in field 25.");
|
||||
}
|
||||
}
|
||||
|
||||
// --- STANDARD VISNING (For alle andre skjemaer) ---
|
||||
StringBuilder htmlBuilder = new StringBuilder();
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
appendBasicInfo(entry, htmlBuilder, textBuilder);
|
||||
showFinalDialog(htmlBuilder, textBuilder);
|
||||
}
|
||||
|
||||
// Hjelpemetode for å legge til info fra hovedskjemaet
|
||||
private void appendBasicInfo(JSONObject entry, StringBuilder html, StringBuilder text) {
|
||||
try {
|
||||
String date = entry.optString("date_created");
|
||||
html.append("<b>Innsendt:</b> ").append(date).append("<br><br>");
|
||||
text.append("Innsendt: ").append(date).append("\n\n");
|
||||
|
||||
// Dato
|
||||
details.append("<b>Innsendt:</b> ").append(entry.optString("date_created")).append("<br><br>");
|
||||
// Iterer gjennom feltene i skjema-definisjonen for å få riktig rekkefølge
|
||||
if (currentForm != null && currentForm.fields != null) {
|
||||
for (GravityField field : currentForm.fields) {
|
||||
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;
|
||||
|
||||
String value = "";
|
||||
if (field.inputs != null && !field.inputs.isEmpty()) {
|
||||
// Composite fields (Address, Name)
|
||||
for (GravityField input : field.inputs) {
|
||||
String subVal = entry.optString(input.id);
|
||||
if (!subVal.isEmpty()) {
|
||||
value += " " + subVal;
|
||||
}
|
||||
if (!subVal.isEmpty()) value += " " + subVal;
|
||||
}
|
||||
} else {
|
||||
// Standard field
|
||||
value = entry.optString(String.valueOf(field.id));
|
||||
}
|
||||
|
||||
if (!value.trim().isEmpty()) {
|
||||
// For filopplastinger er verdien ofte en URL.
|
||||
if ("fileupload".equals(field.type)) {
|
||||
value = "(Vedlegg)";
|
||||
// Håndter filopplastinger (single/multiple)
|
||||
// Her antar vi enkel URL, men for sikkerhets skyld bruker vi extractUrl
|
||||
String cleanUrl = extractUrl(value);
|
||||
if (cleanUrl.startsWith("http")) {
|
||||
html.append("<b>").append(field.label).append(":</b><br>")
|
||||
.append("<a href=\"").append(cleanUrl).append("\">Åpne fil</a><br><br>");
|
||||
text.append(field.label).append(":\n").append(cleanUrl).append("\n\n");
|
||||
} else {
|
||||
html.append("<b>").append(field.label).append(":</b><br>").append(value).append("<br><br>");
|
||||
text.append(field.label).append(":\n").append(value).append("\n\n");
|
||||
}
|
||||
} else {
|
||||
html.append("<b>").append(field.label).append(":</b><br>").append(value).append("<br><br>");
|
||||
text.append(field.label).append(":\n").append(value).append("\n\n");
|
||||
}
|
||||
|
||||
details.append("<b>").append(field.label).append(":</b><br>")
|
||||
.append(value).append("<br><br>");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
details.append("Kunne ikke vise detaljer.");
|
||||
// Rekursiv metode for å hente barn-oppføringer (Vedlegg)
|
||||
private void fetchChildEntriesRecursive(List<String> 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<JsonElement>() {
|
||||
@Override
|
||||
public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> 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() : "";
|
||||
|
||||
html.append("<b>Vedlegg ").append(index + 1).append(":</b><br>");
|
||||
text.append("Vedlegg ").append(index + 1).append(":\n");
|
||||
|
||||
html.append(desc).append(" (").append(price).append(")<br>");
|
||||
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("\\/", "/");
|
||||
html.append("<a href=\"").append(url).append("\">Åpne fil ").append(i+1).append("</a><br>");
|
||||
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 {
|
||||
JSONArray arr = new JSONArray(rawString);
|
||||
for (int i = 0; i < arr.length(); i++) {
|
||||
String url = arr.getString(i).replace("\\/", "/");
|
||||
html.append("<a href=\"").append(url).append("\">Åpne fil ").append(i+1).append("</a><br>");
|
||||
text.append(url).append("\n");
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// Fallback: simple cleanup
|
||||
String clean = extractUrl(rawString);
|
||||
html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
|
||||
text.append(clean).append("\n");
|
||||
}
|
||||
} else {
|
||||
// Just a plain URL string
|
||||
String clean = extractUrl(rawString);
|
||||
if(clean.startsWith("http")) {
|
||||
html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
|
||||
text.append(clean).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
html.append("<br>");
|
||||
text.append("\n");
|
||||
|
||||
} 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<JsonElement> call, Throwable t) {
|
||||
Log.e(TAG, "Network error fetching child entry", t);
|
||||
// Hopp over ved feil
|
||||
fetchChildEntriesRecursive(ids, index + 1, html, text, loader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showFinalDialog(StringBuilder htmlBuilder, StringBuilder textBuilder) {
|
||||
ScrollView scroll = new ScrollView(getContext());
|
||||
TextView text = new TextView(getContext());
|
||||
text.setText(Html.fromHtml(details.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||
text.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());
|
||||
text.setText(Html.fromHtml(htmlBuilder.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||
text.setPadding(40, 40, 40, 40);
|
||||
scroll.addView(text);
|
||||
|
||||
|
|
@ -1435,9 +1593,31 @@ public class FormsFragment extends Fragment {
|
|||
.setTitle("Detaljer")
|
||||
.setView(scroll)
|
||||
.setPositiveButton("Lukk", null)
|
||||
.setNeutralButton("Del", (d, w) -> shareEntryDetails(textBuilder.toString()))
|
||||
.create()
|
||||
.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("[", "")
|
||||
.replace("]", "")
|
||||
.replace("\"", "")
|
||||
.replace("\\/", "/");
|
||||
return clean.trim();
|
||||
}
|
||||
|
||||
private void shareEntryDetails(String text) {
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
|
||||
sendIntent.setType("text/plain");
|
||||
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, "Del innsending via...");
|
||||
startActivity(shareIntent);
|
||||
}
|
||||
|
||||
private void prefillFormFromHistory(JSONObject latestEntry) {
|
||||
if (latestEntry == null) return;
|
||||
for (Map.Entry<String, View> entry : inputViews.entrySet()) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// FILSTI: app\src\main\java\com\kbs\kbsintranett\WordPressApiService.java
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
|
@ -14,7 +13,7 @@ import retrofit2.http.Path;
|
|||
import retrofit2.http.Multipart;
|
||||
import retrofit2.http.Part;
|
||||
import retrofit2.http.PartMap;
|
||||
import retrofit2.http.Query; // NYTT
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface WordPressApiService {
|
||||
// 1. Hent nyheter
|
||||
|
|
@ -50,11 +49,15 @@ public interface WordPressApiService {
|
|||
@GET("wp-json/kbs/v1/calendar/events")
|
||||
Call<List<CalendarEvent>> getCalendarEvents();
|
||||
|
||||
// 8. HENT INNSENDINGER (Entries) - NYTT
|
||||
// 8. HENT INNSENDINGER (Entries) - LISTE
|
||||
@GET("wp-json/gf/v2/entries")
|
||||
Call<GravityEntryResponse> getEntries(
|
||||
@Query("form_ids") int formId,
|
||||
@Query("search") String searchJson,
|
||||
@Query("paging[page_size]") int pageSize
|
||||
);
|
||||
|
||||
// 9. HENT ÉN ENKELT INNSENDING (Ny! Brukes for å hente detaljer fra underskjema)
|
||||
@GET("wp-json/gf/v2/entries/{entry_id}")
|
||||
Call<JsonElement> getSingleEntry(@Path("entry_id") String entryId);
|
||||
}
|
||||
|
|
@ -477,6 +477,7 @@ import android.widget.ArrayAdapter;
|
|||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioButton;
|
||||
|
|
@ -496,6 +497,8 @@ import androidx.fragment.app.Fragment;
|
|||
|
||||
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;
|
||||
|
|
@ -518,7 +521,6 @@ import java.util.Map;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
|
@ -548,10 +550,11 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private LinearLayout formContainer;
|
||||
private LinearLayout historyContainer;
|
||||
private View historyWrapper; // Wrapper for historikk-modulen som skal skjules
|
||||
private View historyWrapper; // Wrapper for historikk-modulen
|
||||
private TextView txtStatus;
|
||||
private TextView lblHistory;
|
||||
private ProgressBar loadingSpinner;
|
||||
private ImageView btnToggleHistory;
|
||||
|
||||
// --- HOVEDSKJEMA STATE ---
|
||||
private Map<String, View> fieldWrappers = new HashMap<>();
|
||||
|
|
@ -585,7 +588,6 @@ public class FormsFragment extends Fragment {
|
|||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
filePickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
|
|
@ -597,7 +599,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
takePictureLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.TakePicture(),
|
||||
success -> {
|
||||
|
|
@ -608,7 +609,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
requestPermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
isGranted -> {
|
||||
|
|
@ -625,16 +625,19 @@ public class FormsFragment extends Fragment {
|
|||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
||||
|
||||
formContainer = view.findViewById(R.id.form_container);
|
||||
historyContainer = view.findViewById(R.id.historyContainer);
|
||||
historyWrapper = view.findViewById(R.id.history_wrapper); // Ny referanse
|
||||
historyWrapper = view.findViewById(R.id.history_wrapper);
|
||||
txtStatus = view.findViewById(R.id.txt_status);
|
||||
lblHistory = view.findViewById(R.id.lbl_history);
|
||||
loadingSpinner = view.findViewById(R.id.loading_spinner);
|
||||
|
||||
// --- FIKS FOR NULLPOINTER EXCEPTION ---
|
||||
// Vi sjekker om LayoutTransition finnes, hvis ikke lager vi en ny.
|
||||
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) {
|
||||
|
|
@ -643,7 +646,7 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
transition.enableTransitionType(LayoutTransition.CHANGING);
|
||||
}
|
||||
// --------------------------------------
|
||||
// ----------------------------------------------------------
|
||||
|
||||
if (formContainer == null) {
|
||||
formContainer = new LinearLayout(getContext());
|
||||
|
|
@ -661,32 +664,42 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
// --- UI LOGIKK FOR DELT SKJERM ---
|
||||
|
||||
// Kalles når brukeren interagerer med et felt i skjemaet
|
||||
private void expandFormModule() {
|
||||
if (historyWrapper != null && historyWrapper.getVisibility() == View.VISIBLE) {
|
||||
historyWrapper.setVisibility(View.GONE);
|
||||
if (btnToggleHistory != null) {
|
||||
btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleHistoryVisibility() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void attachInteractionListener(View view) {
|
||||
if (view == null) return;
|
||||
|
||||
// Touch listener fanger opp klikk før tastaturet kommer opp
|
||||
view.setOnTouchListener((v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
expandFormModule();
|
||||
}
|
||||
return false; // Return false to allow normal processing
|
||||
return false;
|
||||
});
|
||||
|
||||
// Focus listener for edittexts etc
|
||||
view.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
expandFormModule();
|
||||
}
|
||||
});
|
||||
|
||||
// Click listener for buttons/checkboxes
|
||||
if (view.isClickable()) {
|
||||
view.setOnClickListener(v -> expandFormModule());
|
||||
}
|
||||
|
|
@ -736,7 +749,10 @@ public class FormsFragment extends Fragment {
|
|||
updateStatus("");
|
||||
|
||||
// Reset visibility of history on new load
|
||||
if (historyWrapper != null) historyWrapper.setVisibility(View.VISIBLE);
|
||||
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));
|
||||
|
|
@ -755,7 +771,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
|
||||
if (form.fields == null) return;
|
||||
|
||||
for (GravityField field : form.fields) {
|
||||
if ("hidden".equals(field.type) || field.isHidden || "hidden".equals(field.visibility)) {
|
||||
continue;
|
||||
|
|
@ -869,7 +884,8 @@ public class FormsFragment extends Fragment {
|
|||
childFormId = Integer.parseInt(field.gpnfForm);
|
||||
} catch (NumberFormatException e) { e.printStackTrace(); }
|
||||
}
|
||||
openChildFormDialog(childFormId);
|
||||
// NYTT: Sender med felt-ID fra hovedskjemaet (f.eks "25")
|
||||
openChildFormDialog(childFormId, field.id);
|
||||
});
|
||||
container.addView(btnAdd);
|
||||
|
||||
|
|
@ -887,7 +903,8 @@ public class FormsFragment extends Fragment {
|
|||
container.addView(totalAmountView);
|
||||
}
|
||||
|
||||
private void openChildFormDialog(int childFormId) {
|
||||
// NY SIGNATUR: Tar imot parentFieldId
|
||||
private void openChildFormDialog(int childFormId, String parentFieldId) {
|
||||
if (getActivity() == null) return;
|
||||
ProgressBar pBar = new ProgressBar(getContext());
|
||||
AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
|
||||
|
|
@ -895,13 +912,12 @@ public class FormsFragment extends Fragment {
|
|||
.setMessage("Laster skjema...")
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
|
||||
RetrofitClient.getApiService().getForm(childFormId).enqueue(new retrofit2.Callback<GravityForm>() {
|
||||
@Override
|
||||
public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
|
||||
loadingDialog.dismiss();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
showChildFormDialog(response.body());
|
||||
showChildFormDialog(response.body(), parentFieldId);
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Kunne ikke hente underskjema", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
|
@ -915,9 +931,9 @@ public class FormsFragment extends Fragment {
|
|||
});
|
||||
}
|
||||
|
||||
private void showChildFormDialog(GravityForm childForm) {
|
||||
// NY SIGNATUR: Tar imot parentFieldId
|
||||
private void showChildFormDialog(GravityForm childForm, String parentFieldId) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
|
||||
childInputViews.clear();
|
||||
childRequiredFieldsMap.clear();
|
||||
childFileUploads.clear();
|
||||
|
|
@ -927,10 +943,8 @@ public class FormsFragment extends Fragment {
|
|||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.setPadding(30, 30, 30, 30);
|
||||
scrollView.addView(layout);
|
||||
|
||||
for (GravityField field : childForm.fields) {
|
||||
if ("hidden".equals(field.type) || field.isHidden) continue;
|
||||
|
||||
LinearLayout wrapper = new LinearLayout(getContext());
|
||||
wrapper.setOrientation(LinearLayout.VERTICAL);
|
||||
wrapper.setPadding(0, 10, 0, 20);
|
||||
|
|
@ -941,7 +955,6 @@ public class FormsFragment extends Fragment {
|
|||
label.setText(lText);
|
||||
label.setTypeface(null, Typeface.BOLD);
|
||||
wrapper.addView(label);
|
||||
|
||||
if ("fileupload".equals(field.type)) {
|
||||
renderFileUploadField(wrapper, field, childInputViews, childRequiredFieldsMap, true);
|
||||
} else if ("product".equals(field.type)) {
|
||||
|
|
@ -964,11 +977,12 @@ public class FormsFragment extends Fragment {
|
|||
dialog.show();
|
||||
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
|
||||
submitChildForm(childForm.id, dialog);
|
||||
submitChildForm(childForm.id, dialog, parentFieldId);
|
||||
});
|
||||
}
|
||||
|
||||
private void submitChildForm(int childFormId, AlertDialog dialog) {
|
||||
// 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<String, View> entry : childInputViews.entrySet()) {
|
||||
String val = getInputValueGeneric(entry.getValue());
|
||||
|
|
@ -992,6 +1006,15 @@ public class FormsFragment extends Fragment {
|
|||
textParts.put(key, RequestBody.create(MultipartBody.FORM, val));
|
||||
}
|
||||
}
|
||||
|
||||
// --- 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<String, Uri> fileEntry : childFileUploads.entrySet()) {
|
||||
String fieldId = fileEntry.getKey();
|
||||
Uri uri = fileEntry.getValue();
|
||||
|
|
@ -1015,7 +1038,6 @@ public class FormsFragment extends Fragment {
|
|||
// ID 3 = Beskrivelse, ID 4 = Beløp
|
||||
String desc = getInputValueGeneric(childInputViews.get("3"));
|
||||
String price = getInputValueGeneric(childInputViews.get("4"));
|
||||
|
||||
addNestedEntry(entryId, desc, price);
|
||||
dialog.dismiss();
|
||||
} else {
|
||||
|
|
@ -1156,7 +1178,6 @@ public class FormsFragment extends Fragment {
|
|||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
File image = File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
|
||||
return FileProvider.getUriForFile(requireContext(), "com.kbs.kbsintranett.fileprovider", image);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -1258,7 +1279,6 @@ 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
|
||||
|
||||
container.addView(input);
|
||||
|
|
@ -1300,7 +1320,6 @@ public class FormsFragment extends Fragment {
|
|||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
|
||||
container.addView(group);
|
||||
views.put(field.id, group);
|
||||
req.put(field.id, field.isRequired);
|
||||
|
|
@ -1315,7 +1334,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
List<String> labels = new ArrayList<>();
|
||||
labels.add("- Velg -");
|
||||
if (field.choices != null) {
|
||||
|
|
@ -1335,12 +1353,10 @@ public class FormsFragment extends Fragment {
|
|||
String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
|
||||
|
||||
checkBox.setTag("1");
|
||||
|
||||
checkBox.setOnCheckedChangeListener((b, c) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
|
||||
container.addView(checkBox);
|
||||
views.put(inputId, checkBox);
|
||||
req.put(inputId, field.isRequired);
|
||||
|
|
@ -1353,12 +1369,12 @@ public class FormsFragment extends Fragment {
|
|||
CheckBox checkBox = new CheckBox(getContext());
|
||||
checkBox.setText(inputDef.label);
|
||||
|
||||
String value = "1"; // Fallback
|
||||
String value = "1";
|
||||
// Fallback
|
||||
if (field.choices != null && i < field.choices.size()) {
|
||||
value = field.choices.get(i).value;
|
||||
}
|
||||
checkBox.setTag(value);
|
||||
|
||||
checkBox.setOnCheckedChangeListener((b, c) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
|
|
@ -1442,7 +1458,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
|
||||
attachInteractionListener(subInput);
|
||||
|
||||
container.addView(subInput);
|
||||
views.put(subField.id, subInput);
|
||||
req.put(subField.id, isSubRequired);
|
||||
|
|
@ -1511,7 +1526,8 @@ public class FormsFragment extends Fragment {
|
|||
aggregatedResult = aggregatedResult && ruleMatch;
|
||||
if (!aggregatedResult) break;
|
||||
} else {
|
||||
aggregatedResult = aggregatedResult || ruleMatch;
|
||||
aggregatedResult = aggregatedResult ||
|
||||
ruleMatch;
|
||||
if (aggregatedResult) break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1555,7 +1571,8 @@ public class FormsFragment extends Fragment {
|
|||
if (view instanceof CheckBox) {
|
||||
CheckBox cb = (CheckBox) view;
|
||||
if (cb.isChecked()) {
|
||||
return cb.getTag() != null ? cb.getTag().toString() : "1";
|
||||
return cb.getTag() != null ?
|
||||
cb.getTag().toString() : "1";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
@ -1632,11 +1649,11 @@ public class FormsFragment extends Fragment {
|
|||
String url = BASE_URL_GF + "/forms/" + formId + "/submissions";
|
||||
Request request = new Request.Builder().url(url).post(body).header("Cookie", cookie).build();
|
||||
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||
public void onFailure(Call call, IOException e) {
|
||||
public void onFailure(okhttp3.Call call, IOException e) {
|
||||
Log.e(TAG, "JSON submit failed", e);
|
||||
updateStatus("Feil: " + e.getMessage());
|
||||
}
|
||||
public void onResponse(Call call, Response response) {
|
||||
public void onResponse(okhttp3.Call call, Response response) {
|
||||
Log.d(TAG, "JSON response code: " + response.code());
|
||||
if (response.isSuccessful()) {
|
||||
if (getActivity() != null) getActivity().runOnUiThread(() -> {
|
||||
|
|
@ -1720,13 +1737,16 @@ public class FormsFragment extends Fragment {
|
|||
InputStream inputStream = getContext().getContentResolver().openInputStream(uri);
|
||||
String fileName = getFileName(uri);
|
||||
RequestBody requestBody = new RequestBody() {
|
||||
@Override public MediaType contentType() { return MediaType.parse("application/octet-stream"); }
|
||||
@Override public MediaType contentType() { return MediaType.parse("application/octet-stream");
|
||||
}
|
||||
@Override public void writeTo(BufferedSink sink) throws IOException {
|
||||
try (Source source = Okio.source(inputStream)) { sink.writeAll(source); }
|
||||
try (Source source = Okio.source(inputStream)) { sink.writeAll(source);
|
||||
}
|
||||
}
|
||||
};
|
||||
return MultipartBody.Part.createFormData(partName, fileName, requestBody);
|
||||
} catch (Exception e) { return null; }
|
||||
} catch (Exception e) { return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchFormEntries() {
|
||||
|
|
@ -1746,12 +1766,12 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
public void onFailure(@NonNull okhttp3.Call call, @NonNull IOException e) {
|
||||
Log.e(TAG, "Kunne ikke hente historikk", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
public void onResponse(@NonNull okhttp3.Call call, @NonNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
String jsonStr = response.body().string();
|
||||
try {
|
||||
|
|
@ -1761,7 +1781,8 @@ public class FormsFragment extends Fragment {
|
|||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
showHistory(entries);
|
||||
if (formId == ID_ANSATTEOPPLYSNINGER && entries.length() > 0) {
|
||||
if (formId == ID_ANSATTEOPPLYSNINGER && entries.length() > 0)
|
||||
{
|
||||
try {
|
||||
prefillFormFromHistory(entries.getJSONObject(0));
|
||||
} catch (JSONException e) { e.printStackTrace(); }
|
||||
|
|
@ -1769,7 +1790,8 @@ public class FormsFragment extends Fragment {
|
|||
});
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) { e.printStackTrace(); }
|
||||
} catch (JSONException e) { e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1795,16 +1817,13 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
// 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));
|
||||
line.setBackgroundColor(Color.LTGRAY);
|
||||
|
|
@ -1812,57 +1831,209 @@ public class FormsFragment extends Fragment {
|
|||
historyContainer.addView(item);
|
||||
historyContainer.addView(line);
|
||||
}
|
||||
} catch (JSONException e) { e.printStackTrace(); }
|
||||
} catch (JSONException e) { e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// NY METODE: Vis detaljer i dialog
|
||||
// NY METODE: Vis detaljer i dialog med delingsknapp
|
||||
private void showEntryDetails(JSONObject entry) {
|
||||
StringBuilder details = new StringBuilder();
|
||||
// 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
|
||||
|
||||
if (!nestedIds.isEmpty()) {
|
||||
Log.d(TAG, "Nested IDs found: " + nestedIds);
|
||||
List<String> 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<jsonArray.length(); i++) {
|
||||
ids.add(jsonArray.getString(i));
|
||||
}
|
||||
} catch(JSONException e) {
|
||||
Log.e(TAG, "Failed to parse nested IDs as JSON array", e);
|
||||
}
|
||||
} else {
|
||||
// Dette er en komma-separert streng (f.eks "101, 102")
|
||||
for (String id : nestedIds.split(",")) {
|
||||
ids.add(id.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (!ids.isEmpty()) {
|
||||
// Vis en "Laster..." dialog mens vi henter data
|
||||
AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
|
||||
.setMessage("Henter vedleggsdetaljer...")
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
|
||||
// Start rekursiv henting
|
||||
StringBuilder accumulatedHtml = new StringBuilder();
|
||||
StringBuilder accumulatedText = new StringBuilder();
|
||||
|
||||
// Legg først til basis-info fra hovedskjemaet
|
||||
appendBasicInfo(entry, accumulatedHtml, accumulatedText);
|
||||
|
||||
fetchChildEntriesRecursive(ids, 0, accumulatedHtml, accumulatedText, loadingDialog);
|
||||
return; // Stopp her, dialogen vises når data er hentet
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "No nested IDs found in field 25.");
|
||||
}
|
||||
}
|
||||
|
||||
// --- STANDARD VISNING (For alle andre skjemaer) ---
|
||||
StringBuilder htmlBuilder = new StringBuilder();
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
appendBasicInfo(entry, htmlBuilder, textBuilder);
|
||||
showFinalDialog(htmlBuilder, textBuilder);
|
||||
}
|
||||
|
||||
// Hjelpemetode for å legge til info fra hovedskjemaet
|
||||
private void appendBasicInfo(JSONObject entry, StringBuilder html, StringBuilder text) {
|
||||
try {
|
||||
// Loop gjennom alle felter i entry og match med skjema-definisjon
|
||||
// Merk: Entry keys er felt-IDer (f.eks "1", "3.2")
|
||||
String date = entry.optString("date_created");
|
||||
html.append("<b>Innsendt:</b> ").append(date).append("<br><br>");
|
||||
text.append("Innsendt: ").append(date).append("\n\n");
|
||||
|
||||
// Dato
|
||||
details.append("<b>Innsendt:</b> ").append(entry.optString("date_created")).append("<br><br>");
|
||||
|
||||
// Iterer gjennom feltene i skjema-definisjonen for å få riktig rekkefølge
|
||||
if (currentForm != null && currentForm.fields != null) {
|
||||
for (GravityField field : currentForm.fields) {
|
||||
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;
|
||||
|
||||
String value = "";
|
||||
if (field.inputs != null && !field.inputs.isEmpty()) {
|
||||
// Composite fields (Address, Name)
|
||||
for (GravityField input : field.inputs) {
|
||||
String subVal = entry.optString(input.id);
|
||||
if (!subVal.isEmpty()) {
|
||||
value += " " + subVal;
|
||||
}
|
||||
if (!subVal.isEmpty()) value += " " + subVal;
|
||||
}
|
||||
} else {
|
||||
// Standard field
|
||||
value = entry.optString(String.valueOf(field.id));
|
||||
}
|
||||
|
||||
if (!value.trim().isEmpty()) {
|
||||
// For filopplastinger er verdien ofte en URL.
|
||||
if ("fileupload".equals(field.type)) {
|
||||
value = "(Vedlegg)";
|
||||
// Håndter filopplastinger (single/multiple)
|
||||
// Her antar vi enkel URL, men for sikkerhets skyld bruker vi extractUrl
|
||||
String cleanUrl = extractUrl(value);
|
||||
if (cleanUrl.startsWith("http")) {
|
||||
html.append("<b>").append(field.label).append(":</b><br>")
|
||||
.append("<a href=\"").append(cleanUrl).append("\">Åpne fil</a><br><br>");
|
||||
text.append(field.label).append(":\n").append(cleanUrl).append("\n\n");
|
||||
} else {
|
||||
html.append("<b>").append(field.label).append(":</b><br>").append(value).append("<br><br>");
|
||||
text.append(field.label).append(":\n").append(value).append("\n\n");
|
||||
}
|
||||
} else {
|
||||
html.append("<b>").append(field.label).append(":</b><br>").append(value).append("<br><br>");
|
||||
text.append(field.label).append(":\n").append(value).append("\n\n");
|
||||
}
|
||||
|
||||
details.append("<b>").append(field.label).append(":</b><br>")
|
||||
.append(value).append("<br><br>");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
details.append("Kunne ikke vise detaljer.");
|
||||
// Rekursiv metode for å hente barn-oppføringer (Vedlegg)
|
||||
private void fetchChildEntriesRecursive(List<String> 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<JsonElement>() {
|
||||
@Override
|
||||
public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> 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() : "";
|
||||
|
||||
html.append("<b>Vedlegg ").append(index + 1).append(":</b><br>");
|
||||
text.append("Vedlegg ").append(index + 1).append(":\n");
|
||||
|
||||
html.append(desc).append(" (").append(price).append(")<br>");
|
||||
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("\\/", "/");
|
||||
html.append("<a href=\"").append(url).append("\">Åpne fil ").append(i+1).append("</a><br>");
|
||||
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 {
|
||||
JSONArray arr = new JSONArray(rawString);
|
||||
for (int i = 0; i < arr.length(); i++) {
|
||||
String url = arr.getString(i).replace("\\/", "/");
|
||||
html.append("<a href=\"").append(url).append("\">Åpne fil ").append(i+1).append("</a><br>");
|
||||
text.append(url).append("\n");
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
// Fallback: simple cleanup
|
||||
String clean = extractUrl(rawString);
|
||||
html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
|
||||
text.append(clean).append("\n");
|
||||
}
|
||||
} else {
|
||||
// Just a plain URL string
|
||||
String clean = extractUrl(rawString);
|
||||
if(clean.startsWith("http")) {
|
||||
html.append("<a href=\"").append(clean).append("\">Åpne fil</a><br>");
|
||||
text.append(clean).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
html.append("<br>");
|
||||
text.append("\n");
|
||||
|
||||
} 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<JsonElement> call, Throwable t) {
|
||||
Log.e(TAG, "Network error fetching child entry", t);
|
||||
// Hopp over ved feil
|
||||
fetchChildEntriesRecursive(ids, index + 1, html, text, loader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showFinalDialog(StringBuilder htmlBuilder, StringBuilder textBuilder) {
|
||||
ScrollView scroll = new ScrollView(getContext());
|
||||
TextView text = new TextView(getContext());
|
||||
text.setText(Html.fromHtml(details.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||
text.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());
|
||||
text.setText(Html.fromHtml(htmlBuilder.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||
text.setPadding(40, 40, 40, 40);
|
||||
scroll.addView(text);
|
||||
|
||||
|
|
@ -1870,9 +2041,31 @@ public class FormsFragment extends Fragment {
|
|||
.setTitle("Detaljer")
|
||||
.setView(scroll)
|
||||
.setPositiveButton("Lukk", null)
|
||||
.setNeutralButton("Del", (d, w) -> shareEntryDetails(textBuilder.toString()))
|
||||
.create()
|
||||
.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("[", "")
|
||||
.replace("]", "")
|
||||
.replace("\"", "")
|
||||
.replace("\\/", "/");
|
||||
return clean.trim();
|
||||
}
|
||||
|
||||
private void shareEntryDetails(String text) {
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
|
||||
sendIntent.setType("text/plain");
|
||||
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, "Del innsending via...");
|
||||
startActivity(shareIntent);
|
||||
}
|
||||
|
||||
private void prefillFormFromHistory(JSONObject latestEntry) {
|
||||
if (latestEntry == null) return;
|
||||
for (Map.Entry<String, View> entry : inputViews.entrySet()) {
|
||||
|
|
@ -1933,7 +2126,8 @@ public class FormsFragment extends Fragment {
|
|||
String id;
|
||||
String description;
|
||||
String price;
|
||||
NestedEntry(String id, String d, String p) { this.id = id; this.description = d; this.price = p; }
|
||||
NestedEntry(String id, String d, String p) { this.id = id; this.description = d; this.price = p;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStatus(String msg) {
|
||||
|
|
@ -1968,6 +2162,7 @@ public class FormsListFragment extends Fragment {
|
|||
View view = inflater.inflate(R.layout.fragment_forms_list, container, false);
|
||||
LinearLayout 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);
|
||||
|
|
@ -1999,7 +2194,8 @@ public class FormsListFragment extends Fragment {
|
|||
btn.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("formId", formId);
|
||||
Navigation.findNavController(v).navigate(R.id.nav_forms, bundle);
|
||||
// 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);
|
||||
|
|
@ -3034,7 +3230,6 @@ public class UserManager {
|
|||
============================================================
|
||||
FILSTI: app\src\main\java\com\kbs\kbsintranett\WordPressApiService.java
|
||||
============================================================
|
||||
// FILSTI: app\src\main\java\com\kbs\kbsintranett\WordPressApiService.java
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
|
@ -3050,7 +3245,7 @@ import retrofit2.http.Path;
|
|||
import retrofit2.http.Multipart;
|
||||
import retrofit2.http.Part;
|
||||
import retrofit2.http.PartMap;
|
||||
import retrofit2.http.Query; // NYTT
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface WordPressApiService {
|
||||
// 1. Hent nyheter
|
||||
|
|
@ -3086,13 +3281,17 @@ public interface WordPressApiService {
|
|||
@GET("wp-json/kbs/v1/calendar/events")
|
||||
Call<List<CalendarEvent>> getCalendarEvents();
|
||||
|
||||
// 8. HENT INNSENDINGER (Entries) - NYTT
|
||||
// 8. HENT INNSENDINGER (Entries) - LISTE
|
||||
@GET("wp-json/gf/v2/entries")
|
||||
Call<GravityEntryResponse> getEntries(
|
||||
@Query("form_ids") int formId,
|
||||
@Query("search") String searchJson,
|
||||
@Query("paging[page_size]") int pageSize
|
||||
);
|
||||
|
||||
// 9. HENT ÉN ENKELT INNSENDING (Ny! Brukes for å hente detaljer fra underskjema)
|
||||
@GET("wp-json/gf/v2/entries/{entry_id}")
|
||||
Call<JsonElement> getSingleEntry(@Path("entry_id") String entryId);
|
||||
}
|
||||
|
||||
============================================================
|
||||
|
|
@ -3316,6 +3515,7 @@ FILSTI: app\src\main\res\layout\fragment_forms.xml
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
|
|
@ -3380,10 +3580,22 @@ FILSTI: app\src\main\res\layout\fragment_forms.xml
|
|||
|
||||
<TextView
|
||||
android:id="@+id/txt_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textColor="#666666"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"
|
||||
android:text="" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_toggle_history"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@android:drawable/arrow_up_float"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="4dp"
|
||||
android:contentDescription="Vis/Skjul historikk"
|
||||
app:tint="#666666" />
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
|
|
|
|||
Loading…
Reference in a new issue