Før drastisk endring i FormsListFragment.java
This commit is contained in:
parent
56f14e9b92
commit
00028f10e5
4 changed files with 563 additions and 189 deletions
|
|
@ -1,18 +1,26 @@
|
||||||
package com.kbs.kbsintranett;
|
package com.kbs.kbsintranett;
|
||||||
|
|
||||||
|
import android.app.DatePickerDialog;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
|
import android.text.TextWatcher;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.RadioButton;
|
||||||
|
import android.widget.RadioGroup;
|
||||||
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
|
@ -28,8 +36,8 @@ import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -47,8 +55,10 @@ public class FormsFragment extends Fragment {
|
||||||
private static final String TAG = "FormsFragment";
|
private static final String TAG = "FormsFragment";
|
||||||
private static final String BASE_URL_GF = "https://intranet.kbs.no/wp-json/gf/v2";
|
private static final String BASE_URL_GF = "https://intranet.kbs.no/wp-json/gf/v2";
|
||||||
|
|
||||||
// ID 1 = Ansatteopplysninger (Skal ha autofyll fra historikk)
|
// SKJEMA ID-er
|
||||||
private static final int ID_ANSATTEOPPLYSNINGER = 1;
|
private static final int ID_ANSATTEOPPLYSNINGER = 1;
|
||||||
|
private static final int ID_HMS_BEKREFTELSE = 10;
|
||||||
|
private static final int ID_EGENMELDING = 11;
|
||||||
|
|
||||||
private int formId = 1;
|
private int formId = 1;
|
||||||
|
|
||||||
|
|
@ -58,25 +68,27 @@ public class FormsFragment extends Fragment {
|
||||||
private TextView lblHistory; // Overskriften "Tidligere innsendinger"
|
private TextView lblHistory; // Overskriften "Tidligere innsendinger"
|
||||||
private ProgressBar loadingSpinner;
|
private ProgressBar loadingSpinner;
|
||||||
|
|
||||||
private Map<String, EditText> dynamicFields = new HashMap<>();
|
// Vi lagrer View-objektene for å kunne toggle synlighet (Conditional Logic)
|
||||||
|
// Key = Field ID (f.eks "2", "7.1")
|
||||||
|
private Map<String, View> fieldWrappers = new HashMap<>(); // Beholderen (Label + Input)
|
||||||
|
private Map<String, View> inputViews = new HashMap<>(); // Selve input-feltet (EditText, RadioGroup, etc)
|
||||||
private Map<String, Boolean> requiredFieldsMap = new HashMap<>();
|
private Map<String, Boolean> requiredFieldsMap = new HashMap<>();
|
||||||
|
|
||||||
|
private GravityForm currentForm; // Holder referanse til skjemaet for logikk-sjekk
|
||||||
|
|
||||||
private final OkHttpClient client = new OkHttpClient();
|
private final OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
||||||
|
|
||||||
formContainer = view.findViewById(R.id.form_container);
|
formContainer = view.findViewById(R.id.form_container);
|
||||||
historyContainer = view.findViewById(R.id.historyContainer);
|
historyContainer = view.findViewById(R.id.historyContainer);
|
||||||
txtStatus = view.findViewById(R.id.txt_status);
|
txtStatus = view.findViewById(R.id.txt_status);
|
||||||
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);
|
||||||
|
|
||||||
// Fallback hvis XML feiler
|
|
||||||
if (formContainer == null) {
|
if (formContainer == null) {
|
||||||
// Hvis brukeren ikke har oppdatert XML ennå, unngå krasj
|
|
||||||
formContainer = new LinearLayout(getContext());
|
formContainer = new LinearLayout(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,11 +111,11 @@ public class FormsFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
|
public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
GravityForm form = response.body();
|
currentForm = response.body();
|
||||||
if (getActivity() != null) {
|
if (getActivity() != null) {
|
||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
||||||
renderDynamicForm(form);
|
renderDynamicForm(currentForm);
|
||||||
fetchFormEntries();
|
fetchFormEntries();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +136,8 @@ public class FormsFragment extends Fragment {
|
||||||
private void renderDynamicForm(GravityForm form) {
|
private void renderDynamicForm(GravityForm form) {
|
||||||
if (formContainer == null) return;
|
if (formContainer == null) return;
|
||||||
formContainer.removeAllViews();
|
formContainer.removeAllViews();
|
||||||
dynamicFields.clear();
|
fieldWrappers.clear();
|
||||||
|
inputViews.clear();
|
||||||
requiredFieldsMap.clear();
|
requiredFieldsMap.clear();
|
||||||
updateStatus("");
|
updateStatus("");
|
||||||
|
|
||||||
|
|
@ -146,80 +159,109 @@ public class FormsFragment extends Fragment {
|
||||||
|
|
||||||
if (form.fields == null) return;
|
if (form.fields == null) return;
|
||||||
|
|
||||||
UserManager user = UserManager.getInstance();
|
// Bygg feltene
|
||||||
boolean isPersonaliaSection = true;
|
|
||||||
|
|
||||||
boolean hasFilledName = false;
|
|
||||||
boolean hasFilledEmail = false;
|
|
||||||
boolean hasFilledPhone = false;
|
|
||||||
boolean hasFilledJob = false;
|
|
||||||
|
|
||||||
for (GravityField field : form.fields) {
|
for (GravityField field : form.fields) {
|
||||||
|
// Ignorerte felttyper
|
||||||
if ("hidden".equals(field.type)) continue;
|
if ("hidden".equals(field.type) || field.isHidden || "hidden".equals(field.visibility)) {
|
||||||
if (field.isHidden) continue;
|
|
||||||
if ("hidden".equals(field.visibility)) continue;
|
|
||||||
|
|
||||||
if ("section".equals(field.type)) {
|
|
||||||
String labelLower = field.label.toLowerCase();
|
|
||||||
isPersonaliaSection = labelLower.contains("personalia");
|
|
||||||
addSectionHeader(field.label, field.description);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("html".equals(field.type)) {
|
// Wrapper for hele feltet (Label + Input + Description)
|
||||||
if (field.content != null && field.content.toLowerCase().contains("pårørende")) {
|
LinearLayout fieldWrapper = new LinearLayout(getContext());
|
||||||
isPersonaliaSection = false;
|
fieldWrapper.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
fieldWrapper.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
fieldWrapper.setPadding(0, 10, 0, 20);
|
||||||
|
|
||||||
|
// Lagre referanse til wrapperen basert på Felt-ID
|
||||||
|
fieldWrappers.put(String.valueOf(field.id), fieldWrapper);
|
||||||
|
|
||||||
|
// 1. Seksjoner (Overskrifter)
|
||||||
|
if ("section".equals(field.type)) {
|
||||||
|
addSectionHeader(fieldWrapper, field.label, field.description);
|
||||||
|
formContainer.addView(fieldWrapper);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. HTML-blokker
|
||||||
|
if ("html".equals(field.type)) {
|
||||||
if (field.content != null && !field.content.isEmpty()) {
|
if (field.content != null && !field.content.isEmpty()) {
|
||||||
TextView htmlView = new TextView(getContext());
|
TextView htmlView = new TextView(getContext());
|
||||||
htmlView.setText(Html.fromHtml(field.content, Html.FROM_HTML_MODE_COMPACT));
|
htmlView.setText(Html.fromHtml(field.content, Html.FROM_HTML_MODE_COMPACT));
|
||||||
htmlView.setPadding(0, 40, 0, 10);
|
fieldWrapper.addView(htmlView);
|
||||||
formContainer.addView(htmlView);
|
|
||||||
}
|
}
|
||||||
|
formContainer.addView(fieldWrapper);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.inputs != null && !field.inputs.isEmpty()) {
|
// 3. Label (Overskrift for feltet)
|
||||||
renderCompositeField(field, isPersonaliaSection);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ENKELTFELT
|
|
||||||
TextView label = new TextView(getContext());
|
TextView label = new TextView(getContext());
|
||||||
String labelText = field.label;
|
String labelText = field.label;
|
||||||
if (field.isRequired) labelText += " *";
|
if (field.isRequired) labelText += " *";
|
||||||
label.setText(labelText);
|
label.setText(labelText);
|
||||||
label.setTextColor(Color.DKGRAY);
|
label.setTextColor(Color.DKGRAY);
|
||||||
label.setPadding(0, 25, 0, 5);
|
label.setTypeface(null, Typeface.BOLD);
|
||||||
formContainer.addView(label);
|
label.setPadding(0, 10, 0, 5);
|
||||||
|
fieldWrapper.addView(label);
|
||||||
|
|
||||||
|
// 4. Input-felt basert på type
|
||||||
|
if (field.inputs != null && !field.inputs.isEmpty()) {
|
||||||
|
// Sammensatte felt (Navn, Adresse, Checkbox med inputs)
|
||||||
|
if ("consent".equals(field.type)) {
|
||||||
|
renderConsentField(fieldWrapper, field);
|
||||||
|
} else if ("checkbox".equals(field.type)) {
|
||||||
|
renderCheckboxField(fieldWrapper, field);
|
||||||
|
} else {
|
||||||
|
renderCompositeField(fieldWrapper, field);
|
||||||
|
}
|
||||||
|
} else if ("radio".equals(field.type)) {
|
||||||
|
renderRadioField(fieldWrapper, field);
|
||||||
|
} else if ("select".equals(field.type)) {
|
||||||
|
renderSelectField(fieldWrapper, field);
|
||||||
|
} else if ("textarea".equals(field.type)) {
|
||||||
|
renderTextAreaField(fieldWrapper, field);
|
||||||
|
} else if ("date".equals(field.type)) {
|
||||||
|
renderDateField(fieldWrapper, field);
|
||||||
|
} else if ("consent".equals(field.type)) {
|
||||||
|
renderConsentField(fieldWrapper, field);
|
||||||
|
} else {
|
||||||
|
// Standard tekst, e-post, telefon, nummer
|
||||||
|
renderTextField(fieldWrapper, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Beskrivelse (hvis finnes)
|
||||||
|
if (field.description != null && !field.description.isEmpty()) {
|
||||||
|
TextView desc = new TextView(getContext());
|
||||||
|
desc.setText(Html.fromHtml(field.description, Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
desc.setTextSize(12);
|
||||||
|
desc.setTextColor(Color.GRAY);
|
||||||
|
fieldWrapper.addView(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
formContainer.addView(fieldWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEND-KNAPP
|
||||||
|
Button dynamicSubmit = new Button(getContext());
|
||||||
|
dynamicSubmit.setText("Send inn skjema");
|
||||||
|
dynamicSubmit.setTextColor(Color.WHITE);
|
||||||
|
dynamicSubmit.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
params.setMargins(0, 60, 0, 20);
|
||||||
|
dynamicSubmit.setLayoutParams(params);
|
||||||
|
dynamicSubmit.setOnClickListener(v -> submitDynamicForm());
|
||||||
|
formContainer.addView(dynamicSubmit);
|
||||||
|
|
||||||
|
// Etter at alt er tegnet, kjør en initial sjekk på logikken
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- RENDER METHODS ---
|
||||||
|
|
||||||
|
private void renderTextField(LinearLayout container, GravityField field) {
|
||||||
EditText input = new EditText(getContext());
|
EditText input = new EditText(getContext());
|
||||||
input.setPadding(30, 30, 30, 30);
|
input.setPadding(30, 30, 30, 30);
|
||||||
input.setBackgroundResource(android.R.drawable.edit_text);
|
input.setBackgroundResource(android.R.drawable.edit_text);
|
||||||
|
|
||||||
// Autofyll fra UserManager (Standardinfo som alltid er greit å fylle ut)
|
|
||||||
if (isPersonaliaSection) {
|
|
||||||
String lowerLabel = field.label.toLowerCase();
|
|
||||||
|
|
||||||
if (!hasFilledName && (lowerLabel.equals("navn") || lowerLabel.equals("navn *"))) {
|
|
||||||
input.setText(user.getUserDisplayName());
|
|
||||||
hasFilledName = true;
|
|
||||||
}
|
|
||||||
else if (!hasFilledEmail && lowerLabel.contains("e-post") && lowerLabel.contains("arbeid")) {
|
|
||||||
input.setText(user.getUserEmail());
|
|
||||||
hasFilledEmail = true;
|
|
||||||
}
|
|
||||||
else if (!hasFilledJob && lowerLabel.contains("stilling")) {
|
|
||||||
input.setText(user.getStilling());
|
|
||||||
hasFilledJob = true;
|
|
||||||
}
|
|
||||||
else if (!hasFilledPhone && (lowerLabel.contains("mobil") || lowerLabel.equals("mobiltelefon"))) {
|
|
||||||
input.setText(user.getMobiltelefon());
|
|
||||||
hasFilledPhone = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("number".equals(field.type) || "phone".equals(field.type)) {
|
if ("number".equals(field.type) || "phone".equals(field.type)) {
|
||||||
input.setInputType(InputType.TYPE_CLASS_PHONE);
|
input.setInputType(InputType.TYPE_CLASS_PHONE);
|
||||||
} else if ("email".equals(field.type)) {
|
} else if ("email".equals(field.type)) {
|
||||||
|
|
@ -228,69 +270,211 @@ public class FormsFragment extends Fragment {
|
||||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
formContainer.addView(input);
|
|
||||||
|
|
||||||
if (field.description != null && !field.description.isEmpty()) {
|
|
||||||
addDescription(field.description);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicFields.put(String.valueOf(field.id), input);
|
|
||||||
requiredFieldsMap.put(String.valueOf(field.id), field.isRequired);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SEND-KNAPP
|
|
||||||
Button dynamicSubmit = new Button(getContext());
|
|
||||||
dynamicSubmit.setText("Send inn skjema");
|
|
||||||
dynamicSubmit.setTextColor(Color.WHITE);
|
|
||||||
dynamicSubmit.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
|
||||||
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
);
|
|
||||||
params.setMargins(0, 60, 0, 20);
|
|
||||||
dynamicSubmit.setLayoutParams(params);
|
|
||||||
|
|
||||||
dynamicSubmit.setOnClickListener(v -> submitDynamicForm());
|
|
||||||
formContainer.addView(dynamicSubmit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderCompositeField(GravityField parentField, boolean isPersonaliaSection) {
|
|
||||||
TextView groupLabel = new TextView(getContext());
|
|
||||||
String groupText = parentField.label;
|
|
||||||
if (parentField.isRequired) groupText += " *";
|
|
||||||
groupLabel.setText(groupText);
|
|
||||||
groupLabel.setTextColor(Color.DKGRAY);
|
|
||||||
groupLabel.setTypeface(null, Typeface.BOLD);
|
|
||||||
groupLabel.setPadding(0, 30, 0, 5);
|
|
||||||
formContainer.addView(groupLabel);
|
|
||||||
|
|
||||||
UserManager user = UserManager.getInstance();
|
UserManager user = UserManager.getInstance();
|
||||||
String lowerParentLabel = parentField.label.toLowerCase();
|
String lowerLabel = field.label.toLowerCase();
|
||||||
|
|
||||||
List<GravityField> inputs = new ArrayList<>(parentField.inputs);
|
// Autofyll Logikk
|
||||||
|
if (formId == ID_ANSATTEOPPLYSNINGER) {
|
||||||
|
if (lowerLabel.contains("e-post") && lowerLabel.contains("arbeid")) {
|
||||||
|
input.setText(user.getUserEmail());
|
||||||
|
} else if (lowerLabel.contains("stilling")) {
|
||||||
|
input.setText(user.getStilling());
|
||||||
|
} else if ((lowerLabel.contains("mobil") || lowerLabel.equals("mobiltelefon"))) {
|
||||||
|
input.setText(user.getMobiltelefon());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (formId == ID_HMS_BEKREFTELSE) {
|
||||||
|
if (lowerLabel.contains("e-post")) {
|
||||||
|
input.setText(user.getUserEmail());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (formId == ID_EGENMELDING) {
|
||||||
|
if (lowerLabel.contains("navn")) {
|
||||||
|
input.setText(user.getUserDisplayName());
|
||||||
|
} else if (lowerLabel.contains("stilling")) {
|
||||||
|
input.setText(user.getStilling());
|
||||||
|
} else if (lowerLabel.contains("e-post")) {
|
||||||
|
input.setText(user.getUserEmail());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sortering for adresse
|
// Lytter for å trigge Conditional Logic når tekst endres
|
||||||
if (parentField.type.equals("address")) {
|
input.addTextChangedListener(new TextWatcher() {
|
||||||
Collections.sort(inputs, new Comparator<GravityField>() {
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(GravityField f1, GravityField f2) {
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||||
int s1 = getAddressScore(f1.label);
|
@Override
|
||||||
int s2 = getAddressScore(f2.label);
|
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||||
return Integer.compare(s1, s2);
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
container.addView(input);
|
||||||
|
inputViews.put(field.id, input);
|
||||||
|
requiredFieldsMap.put(field.id, field.isRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderTextAreaField(LinearLayout container, GravityField field) {
|
||||||
|
EditText input = new EditText(getContext());
|
||||||
|
input.setPadding(30, 30, 30, 30);
|
||||||
|
input.setBackgroundResource(android.R.drawable.edit_text);
|
||||||
|
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||||
|
input.setMinLines(3);
|
||||||
|
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
|
||||||
|
|
||||||
|
input.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addView(input);
|
||||||
|
inputViews.put(field.id, input);
|
||||||
|
requiredFieldsMap.put(field.id, field.isRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderRadioField(LinearLayout container, GravityField field) {
|
||||||
|
RadioGroup group = new RadioGroup(getContext());
|
||||||
|
group.setOrientation(RadioGroup.VERTICAL);
|
||||||
|
|
||||||
|
if (field.choices != null) {
|
||||||
|
for (GravityField.Choice choice : field.choices) {
|
||||||
|
RadioButton rb = new RadioButton(getContext());
|
||||||
|
rb.setText(choice.text);
|
||||||
|
rb.setTag(choice.value);
|
||||||
|
group.addView(rb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lytter for Conditional Logic
|
||||||
|
group.setOnCheckedChangeListener((group1, checkedId) -> evaluateAllConditionalLogic());
|
||||||
|
|
||||||
|
container.addView(group);
|
||||||
|
inputViews.put(field.id, group);
|
||||||
|
requiredFieldsMap.put(field.id, field.isRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderSelectField(LinearLayout container, GravityField field) {
|
||||||
|
Spinner spinner = new Spinner(getContext());
|
||||||
|
List<String> labels = new ArrayList<>();
|
||||||
|
labels.add("- Velg -");
|
||||||
|
|
||||||
|
if (field.choices != null) {
|
||||||
|
for (GravityField.Choice c : field.choices) {
|
||||||
|
labels.add(c.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, labels);
|
||||||
|
spinner.setAdapter(adapter);
|
||||||
|
|
||||||
|
container.addView(spinner);
|
||||||
|
inputViews.put(field.id, spinner);
|
||||||
|
requiredFieldsMap.put(field.id, field.isRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderConsentField(LinearLayout container, GravityField field) {
|
||||||
|
CheckBox checkBox = new CheckBox(getContext());
|
||||||
|
String cbText = (field.checkboxLabel != null && !field.checkboxLabel.isEmpty())
|
||||||
|
? field.checkboxLabel
|
||||||
|
: field.label;
|
||||||
|
checkBox.setText(cbText);
|
||||||
|
checkBox.setTextSize(16);
|
||||||
|
checkBox.setPadding(10, 10, 10, 10);
|
||||||
|
|
||||||
|
String inputId = field.id;
|
||||||
|
if (field.inputs != null && !field.inputs.isEmpty()) {
|
||||||
|
inputId = field.inputs.get(0).id;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> evaluateAllConditionalLogic());
|
||||||
|
|
||||||
|
container.addView(checkBox);
|
||||||
|
inputViews.put(inputId, checkBox);
|
||||||
|
requiredFieldsMap.put(inputId, field.isRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderCheckboxField(LinearLayout container, GravityField field) {
|
||||||
|
// I Gravity Forms er checkboxes en liste av inputs hvis det er flere valg.
|
||||||
|
// Hvis det bare er ett valg (som "Jeg bekrefter..."), er det ofte én input.
|
||||||
|
|
||||||
|
// Sjekk om det er inputs
|
||||||
|
if (field.inputs != null) {
|
||||||
|
for (GravityField inputDef : field.inputs) {
|
||||||
|
CheckBox checkBox = new CheckBox(getContext());
|
||||||
|
checkBox.setText(inputDef.label);
|
||||||
|
checkBox.setTextSize(16);
|
||||||
|
checkBox.setPadding(10, 10, 10, 10);
|
||||||
|
|
||||||
|
// Verdien som sendes er vanligvis etiketten hvis den er huket av.
|
||||||
|
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> evaluateAllConditionalLogic());
|
||||||
|
|
||||||
|
container.addView(checkBox);
|
||||||
|
inputViews.put(inputDef.id, checkBox);
|
||||||
|
// Checkboxer er sjeldent individuelt påkrevd i en gruppe, men selve feltet er.
|
||||||
|
// Vi markerer den spesifikke boksen som påkrevd hvis feltet er det og det bare er én.
|
||||||
|
if (field.inputs.size() == 1) {
|
||||||
|
requiredFieldsMap.put(inputDef.id, field.isRequired);
|
||||||
|
} else {
|
||||||
|
// Hvis det er flere, er validering mer komplekst (minst én må velges).
|
||||||
|
// Foreløpig enkel implementasjon.
|
||||||
|
requiredFieldsMap.put(inputDef.id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderDateField(LinearLayout container, GravityField field) {
|
||||||
|
EditText dateInput = new EditText(getContext());
|
||||||
|
dateInput.setPadding(30, 30, 30, 30);
|
||||||
|
dateInput.setBackgroundResource(android.R.drawable.edit_text);
|
||||||
|
dateInput.setFocusable(false); // Hindre tastatur
|
||||||
|
dateInput.setClickable(true); // Tillat klikk
|
||||||
|
dateInput.setHint("dd.mm.yyyy");
|
||||||
|
|
||||||
|
dateInput.setOnClickListener(v -> {
|
||||||
|
final Calendar c = Calendar.getInstance();
|
||||||
|
int year = c.get(Calendar.YEAR);
|
||||||
|
int month = c.get(Calendar.MONTH);
|
||||||
|
int day = c.get(Calendar.DAY_OF_MONTH);
|
||||||
|
|
||||||
|
DatePickerDialog datePickerDialog = new DatePickerDialog(getContext(),
|
||||||
|
(view, year1, monthOfYear, dayOfMonth) -> {
|
||||||
|
// Format: dd.MM.yyyy
|
||||||
|
String selectedDate = String.format(java.util.Locale.getDefault(), "%02d.%02d.%d", dayOfMonth, monthOfYear + 1, year1);
|
||||||
|
dateInput.setText(selectedDate);
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
}, year, month, day);
|
||||||
|
datePickerDialog.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addView(dateInput);
|
||||||
|
inputViews.put(field.id, dateInput);
|
||||||
|
requiredFieldsMap.put(field.id, field.isRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderCompositeField(LinearLayout container, GravityField parentField) {
|
||||||
|
UserManager user = UserManager.getInstance();
|
||||||
|
boolean isPersonalia = (formId == ID_ANSATTEOPPLYSNINGER);
|
||||||
|
|
||||||
|
List<GravityField> inputs = new ArrayList<>(parentField.inputs);
|
||||||
|
if ("address".equals(parentField.type)) {
|
||||||
|
Collections.sort(inputs, (f1, f2) -> Integer.compare(getAddressScore(f1.label), getAddressScore(f2.label)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (GravityField subField : inputs) {
|
for (GravityField subField : inputs) {
|
||||||
if (subField.isHidden) continue;
|
if (subField.isHidden || "hidden".equals(subField.visibility)) continue;
|
||||||
if ("hidden".equals(subField.visibility)) continue;
|
|
||||||
|
|
||||||
TextView subLabel = new TextView(getContext());
|
TextView subLabel = new TextView(getContext());
|
||||||
String subLabelText = subField.label;
|
String subLabelText = subField.label;
|
||||||
|
|
||||||
boolean isSubRequired = parentField.isRequired;
|
boolean isSubRequired = parentField.isRequired;
|
||||||
if (parentField.type.equals("address") && subField.id.endsWith(".2")) {
|
if ("address".equals(parentField.type) && subField.id.endsWith(".2")) {
|
||||||
isSubRequired = false;
|
isSubRequired = false;
|
||||||
}
|
}
|
||||||
if (isSubRequired) subLabelText += " *";
|
if (isSubRequired) subLabelText += " *";
|
||||||
|
|
@ -299,32 +483,47 @@ public class FormsFragment extends Fragment {
|
||||||
subLabel.setTextColor(Color.GRAY);
|
subLabel.setTextColor(Color.GRAY);
|
||||||
subLabel.setTextSize(12);
|
subLabel.setTextSize(12);
|
||||||
subLabel.setPadding(0, 10, 0, 0);
|
subLabel.setPadding(0, 10, 0, 0);
|
||||||
formContainer.addView(subLabel);
|
container.addView(subLabel);
|
||||||
|
|
||||||
EditText subInput = new EditText(getContext());
|
EditText subInput = new EditText(getContext());
|
||||||
subInput.setPadding(30, 30, 30, 30);
|
subInput.setPadding(30, 30, 30, 30);
|
||||||
subInput.setBackgroundResource(android.R.drawable.edit_text);
|
subInput.setBackgroundResource(android.R.drawable.edit_text);
|
||||||
subInput.setInputType(InputType.TYPE_CLASS_TEXT);
|
subInput.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
|
||||||
if (isPersonaliaSection && lowerParentLabel.contains("navn") && !lowerParentLabel.contains("pårørende")) {
|
if (isPersonalia && parentField.label.toLowerCase().contains("navn") && !parentField.label.toLowerCase().contains("pårørende")) {
|
||||||
String lowerSubLabel = subField.label.toLowerCase();
|
String lowerSub = subField.label.toLowerCase();
|
||||||
if (lowerSubLabel.contains("fornavn")) {
|
if (lowerSub.contains("fornavn")) subInput.setText(user.getFirstName());
|
||||||
subInput.setText(user.getFirstName());
|
else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
|
||||||
}
|
|
||||||
else if (lowerSubLabel.contains("etternavn")) {
|
|
||||||
subInput.setText(user.getLastName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formContainer.addView(subInput);
|
container.addView(subInput);
|
||||||
|
inputViews.put(subField.id, subInput);
|
||||||
dynamicFields.put(subField.id, subInput);
|
|
||||||
requiredFieldsMap.put(subField.id, isSubRequired);
|
requiredFieldsMap.put(subField.id, isSubRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentField.description != null && !parentField.description.isEmpty()) {
|
|
||||||
addDescription(parentField.description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addSectionHeader(LinearLayout container, String title, String descText) {
|
||||||
|
TextView sectionHeader = new TextView(getContext());
|
||||||
|
sectionHeader.setText(title);
|
||||||
|
sectionHeader.setTextSize(18);
|
||||||
|
sectionHeader.setTypeface(null, Typeface.BOLD);
|
||||||
|
sectionHeader.setTextColor(Color.parseColor("#0069B3"));
|
||||||
|
sectionHeader.setPadding(0, 20, 0, 5);
|
||||||
|
container.addView(sectionHeader);
|
||||||
|
|
||||||
|
if (descText != null && !descText.isEmpty()) {
|
||||||
|
TextView desc = new TextView(getContext());
|
||||||
|
desc.setText(Html.fromHtml(descText, Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
desc.setTextSize(12);
|
||||||
|
desc.setTextColor(Color.GRAY);
|
||||||
|
container.addView(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
View line = new View(getContext());
|
||||||
|
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 2));
|
||||||
|
line.setBackgroundColor(Color.LTGRAY);
|
||||||
|
line.setPadding(0,0,0,20);
|
||||||
|
container.addView(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getAddressScore(String label) {
|
private int getAddressScore(String label) {
|
||||||
|
|
@ -338,33 +537,103 @@ public class FormsFragment extends Fragment {
|
||||||
return 99;
|
return 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDescription(String text) {
|
// --- CONDITIONAL LOGIC ENGINE ---
|
||||||
TextView desc = new TextView(getContext());
|
|
||||||
desc.setText(Html.fromHtml(text, Html.FROM_HTML_MODE_COMPACT));
|
private void evaluateAllConditionalLogic() {
|
||||||
desc.setTextSize(12);
|
if (currentForm == null || currentForm.fields == null) return;
|
||||||
desc.setTextColor(Color.GRAY);
|
|
||||||
desc.setPadding(5, 5, 5, 0);
|
for (GravityField field : currentForm.fields) {
|
||||||
formContainer.addView(desc);
|
if (field.conditionalLogic == null) {
|
||||||
|
setViewVisibility(field.id, true);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSectionHeader(String title, String descText) {
|
boolean isMatch = evaluateLogic(field.conditionalLogic);
|
||||||
TextView sectionHeader = new TextView(getContext());
|
boolean show = "show".equalsIgnoreCase(field.conditionalLogic.actionType);
|
||||||
sectionHeader.setText(title);
|
boolean shouldBeVisible = (show && isMatch) || (!show && !isMatch);
|
||||||
sectionHeader.setTextSize(18);
|
setViewVisibility(field.id, shouldBeVisible);
|
||||||
sectionHeader.setTypeface(null, Typeface.BOLD);
|
}
|
||||||
sectionHeader.setTextColor(Color.parseColor("#0069B3"));
|
|
||||||
sectionHeader.setPadding(0, 50, 0, 5);
|
|
||||||
formContainer.addView(sectionHeader);
|
|
||||||
|
|
||||||
if (descText != null && !descText.isEmpty()) {
|
|
||||||
addDescription(descText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
View line = new View(getContext());
|
private boolean evaluateLogic(GravityField.ConditionalLogic logic) {
|
||||||
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 2));
|
if (logic.rules == null || logic.rules.isEmpty()) return true;
|
||||||
line.setBackgroundColor(Color.LTGRAY);
|
|
||||||
formContainer.addView(line);
|
boolean isAll = "all".equalsIgnoreCase(logic.logicType);
|
||||||
|
boolean aggregatedResult = isAll;
|
||||||
|
|
||||||
|
for (GravityField.Rule rule : logic.rules) {
|
||||||
|
String val = getInputValue(rule.fieldId);
|
||||||
|
boolean ruleMatch = checkRule(val, rule.operator, rule.value);
|
||||||
|
|
||||||
|
if (isAll) {
|
||||||
|
aggregatedResult = aggregatedResult && ruleMatch;
|
||||||
|
if (!aggregatedResult) break;
|
||||||
|
} else {
|
||||||
|
aggregatedResult = aggregatedResult || ruleMatch;
|
||||||
|
if (aggregatedResult) break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return aggregatedResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkRule(String actualValue, String operator, String targetValue) {
|
||||||
|
if (actualValue == null) actualValue = "";
|
||||||
|
if (targetValue == null) targetValue = "";
|
||||||
|
|
||||||
|
switch (operator.toLowerCase()) {
|
||||||
|
case "is":
|
||||||
|
return actualValue.equalsIgnoreCase(targetValue);
|
||||||
|
case "isnot":
|
||||||
|
return !actualValue.equalsIgnoreCase(targetValue);
|
||||||
|
case "contains":
|
||||||
|
return actualValue.toLowerCase().contains(targetValue.toLowerCase());
|
||||||
|
case "starts_with":
|
||||||
|
return actualValue.toLowerCase().startsWith(targetValue.toLowerCase());
|
||||||
|
case "ends_with":
|
||||||
|
return actualValue.toLowerCase().endsWith(targetValue.toLowerCase());
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getInputValue(String fieldId) {
|
||||||
|
View view = inputViews.get(fieldId);
|
||||||
|
if (view == null) return "";
|
||||||
|
|
||||||
|
if (view instanceof EditText) {
|
||||||
|
return ((EditText) view).getText().toString();
|
||||||
|
} else if (view instanceof RadioGroup) {
|
||||||
|
RadioGroup group = (RadioGroup) view;
|
||||||
|
int checkedId = group.getCheckedRadioButtonId();
|
||||||
|
if (checkedId != -1) {
|
||||||
|
View rb = group.findViewById(checkedId);
|
||||||
|
if (rb != null && rb.getTag() != null) {
|
||||||
|
return rb.getTag().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (view instanceof Spinner) {
|
||||||
|
Spinner spinner = (Spinner) view;
|
||||||
|
Object item = spinner.getSelectedItem();
|
||||||
|
return item != null ? item.toString() : "";
|
||||||
|
} else if (view instanceof CheckBox) {
|
||||||
|
CheckBox cb = (CheckBox) view;
|
||||||
|
// Hvis sjekket: returner teksten på boksen eller "1" (for consent)
|
||||||
|
// For standard checkbox i GF brukes ofte verdien som er valgt.
|
||||||
|
// Hvis det er en enkel avkryssing (type "Bekreftelse"), er "Ja" eller "1" vanlig.
|
||||||
|
// Vi returnerer teksten hvis den er sjekket, ellers tom streng.
|
||||||
|
return cb.isChecked() ? cb.getText().toString() : "";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setViewVisibility(String fieldId, boolean visible) {
|
||||||
|
View wrapper = fieldWrappers.get(fieldId);
|
||||||
|
if (wrapper != null) {
|
||||||
|
wrapper.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- DATA HANDLING ---
|
||||||
|
|
||||||
private void fetchFormEntries() {
|
private void fetchFormEntries() {
|
||||||
UserManager user = UserManager.getInstance();
|
UserManager user = UserManager.getInstance();
|
||||||
|
|
@ -404,8 +673,8 @@ public class FormsFragment extends Fragment {
|
||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
showHistory(entries);
|
showHistory(entries);
|
||||||
|
|
||||||
// VIKTIG: AUTO-FYLL SKJER NÅ KUN FOR SKJEMA ID 1
|
// VIKTIG: AUTO-FYLL SKJER KUN FOR SKJEMA ID 1 ("Ansatteopplysninger")
|
||||||
if (entries.length() > 0 && formId == ID_ANSATTEOPPLYSNINGER) {
|
if (formId == ID_ANSATTEOPPLYSNINGER && entries.length() > 0) {
|
||||||
try {
|
try {
|
||||||
prefillFormFromHistory(entries.getJSONObject(0));
|
prefillFormFromHistory(entries.getJSONObject(0));
|
||||||
} catch (JSONException e) { e.printStackTrace(); }
|
} catch (JSONException e) { e.printStackTrace(); }
|
||||||
|
|
@ -420,35 +689,74 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prefillFormFromHistory(JSONObject latestEntry) {
|
private void prefillFormFromHistory(JSONObject latestEntry) {
|
||||||
for (Map.Entry<String, EditText> mapEntry : dynamicFields.entrySet()) {
|
if (latestEntry == null) return;
|
||||||
String fieldId = mapEntry.getKey();
|
|
||||||
EditText input = mapEntry.getValue();
|
|
||||||
|
|
||||||
if (input.getText().length() > 0) continue;
|
for (Map.Entry<String, View> entry : inputViews.entrySet()) {
|
||||||
|
String fieldId = entry.getKey();
|
||||||
|
View view = entry.getValue();
|
||||||
|
|
||||||
if (latestEntry.has(fieldId)) {
|
if (latestEntry.has(fieldId)) {
|
||||||
String prevValue = latestEntry.optString(fieldId);
|
String value = latestEntry.optString(fieldId);
|
||||||
if (!prevValue.isEmpty()) {
|
if (value == null || value.isEmpty()) continue;
|
||||||
input.setText(prevValue);
|
|
||||||
|
if (view instanceof EditText) {
|
||||||
|
((EditText) view).setText(value);
|
||||||
|
} else if (view instanceof RadioGroup) {
|
||||||
|
RadioGroup group = (RadioGroup) view;
|
||||||
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
|
View child = group.getChildAt(i);
|
||||||
|
if (child instanceof RadioButton) {
|
||||||
|
Object tag = child.getTag();
|
||||||
|
if (tag != null && tag.toString().equalsIgnoreCase(value)) {
|
||||||
|
((RadioButton) child).setChecked(true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateStatus("Skjemaet er forhåndsutfylt fra din forrige innsending.");
|
} else if (view instanceof CheckBox) {
|
||||||
|
// For Consent er value "1" = Checked.
|
||||||
|
// For vanlig checkbox kan det være verdien av valget.
|
||||||
|
if ("1".equals(value) || "true".equalsIgnoreCase(value) || ((CheckBox)view).getText().toString().equals(value)) {
|
||||||
|
((CheckBox) view).setChecked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateStatus("Skjemaet er forhåndsutfylt fra din siste innsending.");
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void submitDynamicForm() {
|
private void submitDynamicForm() {
|
||||||
JSONObject inputValues = new JSONObject();
|
JSONObject inputValues = new JSONObject();
|
||||||
boolean hasValues = false;
|
boolean hasValues = false;
|
||||||
|
|
||||||
for (Map.Entry<String, EditText> entry : dynamicFields.entrySet()) {
|
for (Map.Entry<String, View> entry : inputViews.entrySet()) {
|
||||||
String fieldId = entry.getKey();
|
String fieldId = entry.getKey();
|
||||||
EditText input = entry.getValue();
|
View view = entry.getValue();
|
||||||
String value = input.getText().toString().trim();
|
|
||||||
|
|
||||||
|
// Hopp over hvis feltet er skjult av Conditional Logic
|
||||||
|
View wrapper = fieldWrappers.get(fieldId);
|
||||||
|
// Hvis wrapper er null (f.eks sub-input), sjekk parent wrapper
|
||||||
|
if (wrapper == null) {
|
||||||
|
// Forenklet sjekk: hvis selve viewet ikke vises på skjermen
|
||||||
|
if (!view.isShown()) continue;
|
||||||
|
} else {
|
||||||
|
if (wrapper.getVisibility() != View.VISIBLE) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = getInputValue(fieldId);
|
||||||
|
|
||||||
|
// Validering
|
||||||
Boolean isRequired = requiredFieldsMap.get(fieldId);
|
Boolean isRequired = requiredFieldsMap.get(fieldId);
|
||||||
if (isRequired != null && isRequired && value.isEmpty()) {
|
if (isRequired != null && isRequired && value.isEmpty()) {
|
||||||
input.setError("Må fylles ut");
|
if (view instanceof EditText) {
|
||||||
input.requestFocus();
|
((EditText) view).setError("Må fylles ut");
|
||||||
|
view.requestFocus();
|
||||||
|
} else if (view instanceof CheckBox) {
|
||||||
|
Toast.makeText(getContext(), "Du må bekrefte " + ((CheckBox)view).getText(), Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Vennligst fyll ut alle obligatoriske felt.", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -477,7 +785,6 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
Request request = new Request.Builder().url(url).post(body).header("Cookie", cookie).build();
|
Request request = new Request.Builder().url(url).post(body).header("Cookie", cookie).build();
|
||||||
|
|
||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||||
|
|
@ -492,6 +799,9 @@ public class FormsFragment extends Fragment {
|
||||||
Toast.makeText(getContext(), "Skjema sendt!", Toast.LENGTH_LONG).show();
|
Toast.makeText(getContext(), "Skjema sendt!", Toast.LENGTH_LONG).show();
|
||||||
fetchFormEntries();
|
fetchFormEntries();
|
||||||
updateStatus("Innsending OK");
|
updateStatus("Innsending OK");
|
||||||
|
if (formId != ID_ANSATTEOPPLYSNINGER) {
|
||||||
|
clearInputs();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -501,12 +811,20 @@ public class FormsFragment extends Fragment {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clearInputs() {
|
||||||
|
for (View view : inputViews.values()) {
|
||||||
|
if (view instanceof EditText) ((EditText) view).setText("");
|
||||||
|
if (view instanceof RadioGroup) ((RadioGroup) view).clearCheck();
|
||||||
|
if (view instanceof Spinner) ((Spinner) view).setSelection(0);
|
||||||
|
if (view instanceof CheckBox) ((CheckBox) view).setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void showHistory(JSONArray entries) {
|
private void showHistory(JSONArray entries) {
|
||||||
if (historyContainer == null) return;
|
if (historyContainer == null) return;
|
||||||
historyContainer.removeAllViews();
|
historyContainer.removeAllViews();
|
||||||
|
|
||||||
if (entries.length() == 0) {
|
if (entries.length() == 0) {
|
||||||
// Skjul overskriften hvis det ikke er historikk
|
|
||||||
if (lblHistory != null) lblHistory.setVisibility(View.GONE);
|
if (lblHistory != null) lblHistory.setVisibility(View.GONE);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -514,19 +832,19 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < entries.length(); i++) {
|
int count = Math.min(entries.length(), 5);
|
||||||
|
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");
|
||||||
TextView item = new TextView(getContext());
|
TextView item = new TextView(getContext());
|
||||||
item.setText(date);
|
item.setText("Innsendt: " + date);
|
||||||
item.setPadding(10, 20, 10, 20);
|
item.setPadding(10, 20, 10, 20);
|
||||||
|
|
||||||
// Gjør historikken klikkbar (for fremtidig funksjonalitet)
|
|
||||||
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
||||||
|
|
||||||
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));
|
||||||
line.setBackgroundColor(Color.LTGRAY);
|
line.setBackgroundColor(Color.LTGRAY);
|
||||||
|
|
||||||
historyContainer.addView(item);
|
historyContainer.addView(item);
|
||||||
historyContainer.addView(line);
|
historyContainer.addView(line);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package com.kbs.kbsintranett;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
@ -15,8 +17,13 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.navigation.Navigation;
|
import androidx.navigation.Navigation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
|
|
@ -24,6 +31,7 @@ import retrofit2.Response;
|
||||||
|
|
||||||
public class FormsListFragment extends Fragment {
|
public class FormsListFragment extends Fragment {
|
||||||
|
|
||||||
|
private static final String TAG = "FormsListFragment";
|
||||||
private LinearLayout container;
|
private LinearLayout container;
|
||||||
private ProgressBar loadingSpinner;
|
private ProgressBar loadingSpinner;
|
||||||
private TextView txtStatus;
|
private TextView txtStatus;
|
||||||
|
|
@ -31,23 +39,16 @@ public class FormsListFragment extends Fragment {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
// Vi gjenbruker samme layout som detaljvisningen, siden den nå er ryddig
|
|
||||||
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
||||||
|
|
||||||
this.container = view.findViewById(R.id.form_container);
|
this.container = view.findViewById(R.id.form_container);
|
||||||
this.loadingSpinner = view.findViewById(R.id.loading_spinner);
|
this.loadingSpinner = view.findViewById(R.id.loading_spinner);
|
||||||
this.txtStatus = view.findViewById(R.id.txt_status);
|
this.txtStatus = view.findViewById(R.id.txt_status);
|
||||||
|
|
||||||
// Skjul "Tidligere innsendinger" tekst og container på denne siden,
|
View historyTitle = view.findViewById(R.id.historyContainer);
|
||||||
// da vi kun skal vise en meny her.
|
|
||||||
View historyTitle = view.findViewById(R.id.historyContainer); // Egentlig containeren, men vi skjuler alt under
|
|
||||||
if (historyTitle != null) historyTitle.setVisibility(View.GONE);
|
if (historyTitle != null) historyTitle.setVisibility(View.GONE);
|
||||||
|
|
||||||
// Finn og skjul "Tidligere innsendinger" overskriften hvis mulig
|
|
||||||
// (Siden vi bruker en delt XML er dette litt "hacky", men funker)
|
|
||||||
LinearLayout mainLayout = view.findViewById(R.id.main_layout);
|
LinearLayout mainLayout = view.findViewById(R.id.main_layout);
|
||||||
if (mainLayout != null && mainLayout.getChildCount() > 4) {
|
if (mainLayout != null && mainLayout.getChildCount() > 4) {
|
||||||
// Skjuler elementene nederst som hører til historikk
|
|
||||||
for(int i = 0; i < mainLayout.getChildCount(); i++) {
|
for(int i = 0; i < mainLayout.getChildCount(); i++) {
|
||||||
View child = mainLayout.getChildAt(i);
|
View child = mainLayout.getChildAt(i);
|
||||||
if (child instanceof TextView && ((TextView)child).getText().toString().contains("Tidligere")) {
|
if (child instanceof TextView && ((TextView)child).getText().toString().contains("Tidligere")) {
|
||||||
|
|
@ -70,34 +71,56 @@ public class FormsListFragment extends Fragment {
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
||||||
if (txtStatus != null) txtStatus.setText("");
|
if (txtStatus != null) txtStatus.setText("");
|
||||||
|
|
||||||
// Hent listen over skjemaer (Map ID -> Skjema)
|
Log.d(TAG, "Starter henting av skjemaer...");
|
||||||
|
|
||||||
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
|
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
|
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
|
||||||
if (getContext() == null) return;
|
if (getContext() == null) return;
|
||||||
|
|
||||||
// SKJUL SPINNER NÅR VI FÅR SVAR
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
Map<String, GravityForm> formMap = response.body();
|
Map<String, GravityForm> formMap = response.body();
|
||||||
|
Log.d(TAG, "Fant " + formMap.size() + " skjemaer totalt.");
|
||||||
|
|
||||||
if (formMap.isEmpty()) {
|
if (formMap.isEmpty()) {
|
||||||
if (txtStatus != null) txtStatus.setText("Ingen skjemaer funnet.");
|
if (txtStatus != null) txtStatus.setText("Ingen skjemaer funnet.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vi sorterer listen basert på ID (eller tittel) for ryddighet
|
List<GravityForm> visibleForms = new ArrayList<>();
|
||||||
Map<String, GravityForm> sortedMap = new TreeMap<>(formMap);
|
for (GravityForm form : formMap.values()) {
|
||||||
|
boolean isActive = form.isActive == null || !"0".equals(form.isActive);
|
||||||
|
Integer sortOrder = getSortOrderFromDescription(form);
|
||||||
|
|
||||||
for (Map.Entry<String, GravityForm> entry : sortedMap.entrySet()) {
|
// Logg hva vi finner for hvert skjema
|
||||||
GravityForm form = entry.getValue();
|
Log.d(TAG, "Skjema: " + form.title + " | ID: " + form.id + " | Beskrivelse: " + form.description + " | Sorteringstall funnet: " + sortOrder);
|
||||||
// Sjekk at skjemaet er aktivt og har en tittel
|
|
||||||
if (form != null && form.title != null) {
|
if (form != null && form.title != null && isActive && sortOrder != null) {
|
||||||
|
visibleForms.add(form);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visibleForms.isEmpty()) {
|
||||||
|
Log.w(TAG, "Alle skjemaer ble filtrert bort. Sjekk at beskrivelsene starter med et tall.");
|
||||||
|
if (txtStatus != null) txtStatus.setText("Ingen tilgjengelige skjemaer i appen.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorter basert på tallet vi fant
|
||||||
|
Collections.sort(visibleForms, new Comparator<GravityForm>() {
|
||||||
|
@Override
|
||||||
|
public int compare(GravityForm f1, GravityForm f2) {
|
||||||
|
return Integer.compare(getSortOrderFromDescription(f1), getSortOrderFromDescription(f2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (GravityForm form : visibleForms) {
|
||||||
addFormButton(form);
|
addFormButton(form);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
Log.e(TAG, "Feil fra server: " + response.code());
|
||||||
if (txtStatus != null) txtStatus.setText("Kunne ikke laste listen (Kode " + response.code() + ")");
|
if (txtStatus != null) txtStatus.setText("Kunne ikke laste listen (Kode " + response.code() + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -105,34 +128,59 @@ public class FormsListFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
|
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
|
||||||
if (getContext() == null) return;
|
if (getContext() == null) return;
|
||||||
// SKJUL SPINNER VED FEIL
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
||||||
|
Log.e(TAG, "Nettverksfeil", t);
|
||||||
if (txtStatus != null) txtStatus.setText("Nettverksfeil: " + t.getMessage());
|
if (txtStatus != null) txtStatus.setText("Nettverksfeil: " + t.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Leter etter et tall i starten av beskrivelsen.
|
||||||
|
* Håndterer HTML-tags og mellomrom.
|
||||||
|
*/
|
||||||
|
private Integer getSortOrderFromDescription(GravityForm form) {
|
||||||
|
if (form.description == null || form.description.isEmpty()) {
|
||||||
|
return null; // Skjules
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Fjern HTML-tags for å få ren tekst (f.eks "<p>10.</p>" -> "10.")
|
||||||
|
String cleanText = Html.fromHtml(form.description, Html.FROM_HTML_MODE_COMPACT).toString().trim();
|
||||||
|
|
||||||
|
// 2. Regex: Finn første sekvens av tall (\d+)
|
||||||
|
// ^\D* betyr "Start på linjen, ignorer ikke-tall (som bokstaver/tegn) i starten"
|
||||||
|
Pattern p = Pattern.compile("^\\D*(\\d+)");
|
||||||
|
Matcher m = p.matcher(cleanText);
|
||||||
|
|
||||||
|
if (m.find()) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(m.group(1));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; // Ingen tall funnet -> Skjules
|
||||||
|
}
|
||||||
|
|
||||||
private void addFormButton(GravityForm form) {
|
private void addFormButton(GravityForm form) {
|
||||||
Button button = new Button(getContext());
|
Button button = new Button(getContext());
|
||||||
button.setText(form.title.toUpperCase()); // Store bokstaver ser ofte ryddigere ut i menyer
|
button.setText(form.title.toUpperCase());
|
||||||
button.setTextColor(Color.WHITE);
|
button.setTextColor(Color.WHITE);
|
||||||
button.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
button.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||||
button.setTextSize(14);
|
button.setTextSize(14);
|
||||||
button.setPadding(30, 30, 30, 30);
|
button.setPadding(30, 30, 30, 30);
|
||||||
|
|
||||||
// Klikk-lytter
|
|
||||||
button.setOnClickListener(v -> {
|
button.setOnClickListener(v -> {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putInt("formId", form.id);
|
bundle.putInt("formId", form.id);
|
||||||
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Layout parametere (Marginer)
|
|
||||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
);
|
);
|
||||||
params.setMargins(0, 0, 0, 20); // Avstand mellom knappene
|
params.setMargins(0, 0, 0, 20);
|
||||||
button.setLayoutParams(params);
|
button.setLayoutParams(params);
|
||||||
|
|
||||||
container.addView(button);
|
container.addView(button);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,11 @@ public class GravityField {
|
||||||
@SerializedName("label")
|
@SerializedName("label")
|
||||||
public String label;
|
public String label;
|
||||||
|
|
||||||
|
// --- DETTE ER FELTET SOM MANGLER ---
|
||||||
|
@SerializedName("adminLabel")
|
||||||
|
public String adminLabel;
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
@SerializedName("description")
|
@SerializedName("description")
|
||||||
public String description;
|
public String description;
|
||||||
|
|
||||||
|
|
@ -46,7 +51,7 @@ public class GravityField {
|
||||||
@SerializedName("conditionalLogic")
|
@SerializedName("conditionalLogic")
|
||||||
public ConditionalLogic conditionalLogic;
|
public ConditionalLogic conditionalLogic;
|
||||||
|
|
||||||
// NYTT: For å lese Populate Anything-regler
|
// For å lese Populate Anything-regler
|
||||||
@SerializedName("gppa-values-templates")
|
@SerializedName("gppa-values-templates")
|
||||||
public java.util.Map<String, String> gppaTemplates;
|
public java.util.Map<String, String> gppaTemplates;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ public class GravityForm {
|
||||||
@SerializedName("description")
|
@SerializedName("description")
|
||||||
public String description;
|
public String description;
|
||||||
|
|
||||||
|
@SerializedName("is_active")
|
||||||
|
public String isActive; // "1" = Aktiv, "0" = Inaktiv
|
||||||
|
|
||||||
@SerializedName("fields")
|
@SerializedName("fields")
|
||||||
public List<GravityField> fields; // En liste med alle feltene i skjemaet
|
public List<GravityField> fields;
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue