Før lenker til tidligere oppføriner
This commit is contained in:
parent
4e67902021
commit
c23b4ba3d3
6 changed files with 867 additions and 535 deletions
|
|
@ -1,15 +1,19 @@
|
||||||
package com.kbs.kbsintranett;
|
package com.kbs.kbsintranett;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.animation.LayoutTransition;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.DatePickerDialog;
|
import android.app.DatePickerDialog;
|
||||||
import android.app.TimePickerDialog;
|
import android.app.TimePickerDialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
|
|
@ -18,12 +22,14 @@ import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.RadioButton;
|
import android.widget.RadioButton;
|
||||||
|
|
@ -37,6 +43,8 @@ import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.content.FileProvider;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
|
@ -46,6 +54,7 @@ import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
@ -92,9 +101,11 @@ public class FormsFragment extends Fragment {
|
||||||
|
|
||||||
private LinearLayout formContainer;
|
private LinearLayout formContainer;
|
||||||
private LinearLayout historyContainer;
|
private LinearLayout historyContainer;
|
||||||
|
private View historyWrapper; // Wrapper for historikk-modulen
|
||||||
private TextView txtStatus;
|
private TextView txtStatus;
|
||||||
private TextView lblHistory;
|
private TextView lblHistory;
|
||||||
private ProgressBar loadingSpinner;
|
private ProgressBar loadingSpinner;
|
||||||
|
private ImageView btnToggleHistory; // NY: Knapp for å vise/skjule historikk
|
||||||
|
|
||||||
// --- HOVEDSKJEMA STATE ---
|
// --- HOVEDSKJEMA STATE ---
|
||||||
private Map<String, View> fieldWrappers = new HashMap<>();
|
private Map<String, View> fieldWrappers = new HashMap<>();
|
||||||
|
|
@ -110,9 +121,15 @@ public class FormsFragment extends Fragment {
|
||||||
private List<NestedEntry> nestedEntries = new ArrayList<>();
|
private List<NestedEntry> nestedEntries = new ArrayList<>();
|
||||||
private LinearLayout nestedEntriesContainer;
|
private LinearLayout nestedEntriesContainer;
|
||||||
private TextView totalAmountView;
|
private TextView totalAmountView;
|
||||||
|
|
||||||
|
// --- FILOPPLASTING & KAMERA ---
|
||||||
private String pendingFileFieldId = null;
|
private String pendingFileFieldId = null;
|
||||||
private boolean isSelectingForChild = false;
|
private boolean isSelectingForChild = false;
|
||||||
|
private Uri currentPhotoUri = null;
|
||||||
|
|
||||||
private ActivityResultLauncher<Intent> filePickerLauncher;
|
private ActivityResultLauncher<Intent> filePickerLauncher;
|
||||||
|
private ActivityResultLauncher<Uri> takePictureLauncher;
|
||||||
|
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||||
|
|
||||||
private GravityForm currentForm;
|
private GravityForm currentForm;
|
||||||
private final OkHttpClient client = new OkHttpClient();
|
private final OkHttpClient client = new OkHttpClient();
|
||||||
|
|
@ -131,8 +148,26 @@ public class FormsFragment extends Fragment {
|
||||||
handleFileSelection(pendingFileFieldId, uri, isSelectingForChild);
|
handleFileSelection(pendingFileFieldId, uri, isSelectingForChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pendingFileFieldId = null;
|
}
|
||||||
isSelectingForChild = false;
|
);
|
||||||
|
takePictureLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.TakePicture(),
|
||||||
|
success -> {
|
||||||
|
if (success && currentPhotoUri != null && pendingFileFieldId != null) {
|
||||||
|
handleFileSelection(pendingFileFieldId, currentPhotoUri, isSelectingForChild);
|
||||||
|
} else if (!success) {
|
||||||
|
currentPhotoUri = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
requestPermissionLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.RequestPermission(),
|
||||||
|
isGranted -> {
|
||||||
|
if (isGranted) {
|
||||||
|
openCamera();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Kameratillatelse er påkrevd for å ta bilde.", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -143,10 +178,29 @@ public class FormsFragment extends Fragment {
|
||||||
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);
|
||||||
|
historyWrapper = view.findViewById(R.id.history_wrapper);
|
||||||
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);
|
||||||
|
|
||||||
|
// --- 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) {
|
||||||
|
LayoutTransition transition = ((ViewGroup) view).getLayoutTransition();
|
||||||
|
if (transition == null) {
|
||||||
|
transition = new LayoutTransition();
|
||||||
|
((ViewGroup) view).setLayoutTransition(transition);
|
||||||
|
}
|
||||||
|
transition.enableTransitionType(LayoutTransition.CHANGING);
|
||||||
|
}
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
if (formContainer == null) {
|
if (formContainer == null) {
|
||||||
formContainer = new LinearLayout(getContext());
|
formContainer = new LinearLayout(getContext());
|
||||||
}
|
}
|
||||||
|
|
@ -161,6 +215,58 @@ public class FormsFragment extends Fragment {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 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)
|
||||||
|
historyWrapper.setVisibility(View.GONE);
|
||||||
|
btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
|
||||||
|
} else {
|
||||||
|
// Vis historikk (Gå til splitscreen)
|
||||||
|
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
|
||||||
|
});
|
||||||
|
// Focus listener for edittexts etc
|
||||||
|
view.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
|
if (hasFocus) {
|
||||||
|
expandFormModule();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Click listener for buttons/checkboxes
|
||||||
|
if (view.isClickable()) {
|
||||||
|
view.setOnClickListener(v -> expandFormModule());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
private void fetchFormStructure() {
|
private void fetchFormStructure() {
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
||||||
updateStatus("Laster skjema...");
|
updateStatus("Laster skjema...");
|
||||||
|
|
@ -202,6 +308,12 @@ public class FormsFragment extends Fragment {
|
||||||
nestedEntries.clear();
|
nestedEntries.clear();
|
||||||
updateStatus("");
|
updateStatus("");
|
||||||
|
|
||||||
|
// Reset visibility of history on new load (Splitscreen start)
|
||||||
|
if (historyWrapper != null) {
|
||||||
|
historyWrapper.setVisibility(View.VISIBLE);
|
||||||
|
if (btnToggleHistory != null) btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
|
||||||
|
}
|
||||||
|
|
||||||
TextView title = new TextView(getContext());
|
TextView title = new TextView(getContext());
|
||||||
title.setText(getCleanTitle(form.title));
|
title.setText(getCleanTitle(form.title));
|
||||||
title.setTextSize(24);
|
title.setTextSize(24);
|
||||||
|
|
@ -219,7 +331,6 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (form.fields == null) return;
|
if (form.fields == null) return;
|
||||||
|
|
||||||
for (GravityField field : form.fields) {
|
for (GravityField field : form.fields) {
|
||||||
if ("hidden".equals(field.type) || field.isHidden || "hidden".equals(field.visibility)) {
|
if ("hidden".equals(field.type) || field.isHidden || "hidden".equals(field.visibility)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -326,6 +437,7 @@ public class FormsFragment extends Fragment {
|
||||||
btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
|
btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
|
||||||
btnAdd.setTextColor(Color.WHITE);
|
btnAdd.setTextColor(Color.WHITE);
|
||||||
btnAdd.setOnClickListener(v -> {
|
btnAdd.setOnClickListener(v -> {
|
||||||
|
expandFormModule(); // Trigger expand
|
||||||
int childFormId = 18;
|
int childFormId = 18;
|
||||||
if (field.gpnfForm != null) {
|
if (field.gpnfForm != null) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -358,7 +470,6 @@ public class FormsFragment extends Fragment {
|
||||||
.setMessage("Laster skjema...")
|
.setMessage("Laster skjema...")
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show();
|
.show();
|
||||||
|
|
||||||
RetrofitClient.getApiService().getForm(childFormId).enqueue(new retrofit2.Callback<GravityForm>() {
|
RetrofitClient.getApiService().getForm(childFormId).enqueue(new retrofit2.Callback<GravityForm>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
|
public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
|
||||||
|
|
@ -380,8 +491,6 @@ public class FormsFragment extends Fragment {
|
||||||
|
|
||||||
private void showChildFormDialog(GravityForm childForm) {
|
private void showChildFormDialog(GravityForm childForm) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||||
// FJERNET: builder.setTitle(childForm.title); - Brukeren ønsket ikke tittel i popup
|
|
||||||
|
|
||||||
childInputViews.clear();
|
childInputViews.clear();
|
||||||
childRequiredFieldsMap.clear();
|
childRequiredFieldsMap.clear();
|
||||||
childFileUploads.clear();
|
childFileUploads.clear();
|
||||||
|
|
@ -391,10 +500,8 @@ public class FormsFragment extends Fragment {
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
layout.setOrientation(LinearLayout.VERTICAL);
|
||||||
layout.setPadding(30, 30, 30, 30);
|
layout.setPadding(30, 30, 30, 30);
|
||||||
scrollView.addView(layout);
|
scrollView.addView(layout);
|
||||||
|
|
||||||
for (GravityField field : childForm.fields) {
|
for (GravityField field : childForm.fields) {
|
||||||
if ("hidden".equals(field.type) || field.isHidden) continue;
|
if ("hidden".equals(field.type) || field.isHidden) continue;
|
||||||
|
|
||||||
LinearLayout wrapper = new LinearLayout(getContext());
|
LinearLayout wrapper = new LinearLayout(getContext());
|
||||||
wrapper.setOrientation(LinearLayout.VERTICAL);
|
wrapper.setOrientation(LinearLayout.VERTICAL);
|
||||||
wrapper.setPadding(0, 10, 0, 20);
|
wrapper.setPadding(0, 10, 0, 20);
|
||||||
|
|
@ -405,7 +512,6 @@ public class FormsFragment extends Fragment {
|
||||||
label.setText(lText);
|
label.setText(lText);
|
||||||
label.setTypeface(null, Typeface.BOLD);
|
label.setTypeface(null, Typeface.BOLD);
|
||||||
wrapper.addView(label);
|
wrapper.addView(label);
|
||||||
|
|
||||||
if ("fileupload".equals(field.type)) {
|
if ("fileupload".equals(field.type)) {
|
||||||
renderFileUploadField(wrapper, field, childInputViews, childRequiredFieldsMap, true);
|
renderFileUploadField(wrapper, field, childInputViews, childRequiredFieldsMap, true);
|
||||||
} else if ("product".equals(field.type)) {
|
} else if ("product".equals(field.type)) {
|
||||||
|
|
@ -479,7 +585,6 @@ public class FormsFragment extends Fragment {
|
||||||
// ID 3 = Beskrivelse, ID 4 = Beløp
|
// ID 3 = Beskrivelse, ID 4 = Beløp
|
||||||
String desc = getInputValueGeneric(childInputViews.get("3"));
|
String desc = getInputValueGeneric(childInputViews.get("3"));
|
||||||
String price = getInputValueGeneric(childInputViews.get("4"));
|
String price = getInputValueGeneric(childInputViews.get("4"));
|
||||||
|
|
||||||
addNestedEntry(entryId, desc, price);
|
addNestedEntry(entryId, desc, price);
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -542,27 +647,20 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FELLES METODER ---
|
// --- FELLES METODER (FILE UPLOAD M/ CAMERA STØTTE) ---
|
||||||
|
|
||||||
private void renderFileUploadField(LinearLayout container, GravityField field, Map<String, View> viewsMap, Map<String, Boolean> reqMap, boolean isChild) {
|
private void renderFileUploadField(LinearLayout container, GravityField field, Map<String, View> viewsMap, Map<String, Boolean> reqMap, boolean isChild) {
|
||||||
LinearLayout fileLayout = new LinearLayout(getContext());
|
LinearLayout fileLayout = new LinearLayout(getContext());
|
||||||
fileLayout.setOrientation(LinearLayout.HORIZONTAL);
|
fileLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
Button btnUpload = new Button(getContext());
|
Button btnUpload = new Button(getContext());
|
||||||
btnUpload.setText("Velg fil");
|
btnUpload.setText("Velg fil / Ta bilde");
|
||||||
btnUpload.setOnClickListener(v -> {
|
btnUpload.setOnClickListener(v -> {
|
||||||
if (filePickerLauncher == null) return;
|
// Setter state før vi viser dialog
|
||||||
try {
|
pendingFileFieldId = field.id;
|
||||||
pendingFileFieldId = field.id;
|
isSelectingForChild = isChild;
|
||||||
isSelectingForChild = isChild;
|
expandFormModule(); // Trigger expand
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
showFileSourceDialog();
|
||||||
intent.setType("*/*");
|
|
||||||
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
|
||||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
|
||||||
filePickerLauncher.launch(intent);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
TextView txtFileName = new TextView(getContext());
|
TextView txtFileName = new TextView(getContext());
|
||||||
txtFileName.setText("Ingen fil valgt");
|
txtFileName.setText("Ingen fil valgt");
|
||||||
|
|
@ -578,6 +676,62 @@ public class FormsFragment extends Fragment {
|
||||||
reqMap.put(field.id, field.isRequired);
|
reqMap.put(field.id, field.isRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hjelpemetode for å vise dialog
|
||||||
|
private void showFileSourceDialog() {
|
||||||
|
String[] options = {"Ta bilde", "Velg fil"};
|
||||||
|
new AlertDialog.Builder(getContext())
|
||||||
|
.setTitle("Last opp vedlegg")
|
||||||
|
.setItems(options, (dialog, which) -> {
|
||||||
|
if (which == 0) {
|
||||||
|
// Ta bilde - SJEKKER PERMISSION FØRST
|
||||||
|
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
|
||||||
|
== PackageManager.PERMISSION_GRANTED) {
|
||||||
|
openCamera();
|
||||||
|
} else {
|
||||||
|
// Spør om lov
|
||||||
|
requestPermissionLauncher.launch(Manifest.permission.CAMERA);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Velg fil
|
||||||
|
if (filePickerLauncher != null) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
intent.setType("*/*");
|
||||||
|
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
||||||
|
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||||
|
filePickerLauncher.launch(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openCamera() {
|
||||||
|
currentPhotoUri = createImageUri();
|
||||||
|
if (currentPhotoUri != null && takePictureLauncher != null) {
|
||||||
|
try {
|
||||||
|
takePictureLauncher.launch(currentPhotoUri);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(getContext(), "Kunne ikke starte kamera: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
Log.e(TAG, "Camera launch failed", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Kunne ikke opprette bildefil", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Uri createImageUri() {
|
||||||
|
try {
|
||||||
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||||
|
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();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
|
private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
|
||||||
if (isChild) {
|
if (isChild) {
|
||||||
childFileUploads.put(fieldId, uri);
|
childFileUploads.put(fieldId, uri);
|
||||||
|
|
@ -631,6 +785,7 @@ public class FormsFragment extends Fragment {
|
||||||
timeInput.setClickable(true);
|
timeInput.setClickable(true);
|
||||||
timeInput.setHint("00:00");
|
timeInput.setHint("00:00");
|
||||||
timeInput.setOnClickListener(v -> {
|
timeInput.setOnClickListener(v -> {
|
||||||
|
expandFormModule(); // Trigger expand
|
||||||
Calendar mcurrentTime = Calendar.getInstance();
|
Calendar mcurrentTime = Calendar.getInstance();
|
||||||
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
||||||
int minute = mcurrentTime.get(Calendar.MINUTE);
|
int minute = mcurrentTime.get(Calendar.MINUTE);
|
||||||
|
|
@ -671,6 +826,8 @@ public class FormsFragment extends Fragment {
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||||
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
|
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
|
||||||
});
|
});
|
||||||
|
attachInteractionListener(input); // Add listener
|
||||||
|
|
||||||
container.addView(input);
|
container.addView(input);
|
||||||
views.put(field.id, input);
|
views.put(field.id, input);
|
||||||
req.put(field.id, field.isRequired);
|
req.put(field.id, field.isRequired);
|
||||||
|
|
@ -682,6 +839,9 @@ public class FormsFragment extends Fragment {
|
||||||
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||||
input.setMinLines(3);
|
input.setMinLines(3);
|
||||||
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
|
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
|
||||||
|
|
||||||
|
attachInteractionListener(input); // Add listener
|
||||||
|
|
||||||
container.addView(input);
|
container.addView(input);
|
||||||
views.put(field.id, input);
|
views.put(field.id, input);
|
||||||
req.put(field.id, field.isRequired);
|
req.put(field.id, field.isRequired);
|
||||||
|
|
@ -694,10 +854,19 @@ public class FormsFragment extends Fragment {
|
||||||
RadioButton rb = new RadioButton(getContext());
|
RadioButton rb = new RadioButton(getContext());
|
||||||
rb.setText(choice.text);
|
rb.setText(choice.text);
|
||||||
rb.setTag(choice.value);
|
rb.setTag(choice.value);
|
||||||
|
// Also trigger expand on RadioButton click
|
||||||
|
rb.setOnClickListener(v -> {
|
||||||
|
expandFormModule();
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
group.addView(rb);
|
group.addView(rb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group.setOnCheckedChangeListener((g, i) -> evaluateAllConditionalLogic());
|
// Fallback listener
|
||||||
|
group.setOnCheckedChangeListener((g, i) -> {
|
||||||
|
expandFormModule();
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
container.addView(group);
|
container.addView(group);
|
||||||
views.put(field.id, group);
|
views.put(field.id, group);
|
||||||
req.put(field.id, field.isRequired);
|
req.put(field.id, field.isRequired);
|
||||||
|
|
@ -705,6 +874,13 @@ public class FormsFragment extends Fragment {
|
||||||
|
|
||||||
private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
|
private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
|
||||||
Spinner spinner = new Spinner(getContext());
|
Spinner spinner = new Spinner(getContext());
|
||||||
|
// Spinner touch listener is tricky, usually set onTouchListener works
|
||||||
|
spinner.setOnTouchListener((v, event) -> {
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
|
expandFormModule();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
List<String> labels = new ArrayList<>();
|
List<String> labels = new ArrayList<>();
|
||||||
labels.add("- Velg -");
|
labels.add("- Velg -");
|
||||||
if (field.choices != null) {
|
if (field.choices != null) {
|
||||||
|
|
@ -723,10 +899,11 @@ public class FormsFragment extends Fragment {
|
||||||
checkBox.setText(cbText);
|
checkBox.setText(cbText);
|
||||||
String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
|
String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
|
||||||
|
|
||||||
// For Consent fields, Gravity Forms typically expects "1" if checked.
|
|
||||||
checkBox.setTag("1");
|
checkBox.setTag("1");
|
||||||
|
checkBox.setOnCheckedChangeListener((b, c) -> {
|
||||||
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
|
expandFormModule();
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
container.addView(checkBox);
|
container.addView(checkBox);
|
||||||
views.put(inputId, checkBox);
|
views.put(inputId, checkBox);
|
||||||
req.put(inputId, field.isRequired);
|
req.put(inputId, field.isRequired);
|
||||||
|
|
@ -739,17 +916,16 @@ public class FormsFragment extends Fragment {
|
||||||
CheckBox checkBox = new CheckBox(getContext());
|
CheckBox checkBox = new CheckBox(getContext());
|
||||||
checkBox.setText(inputDef.label);
|
checkBox.setText(inputDef.label);
|
||||||
|
|
||||||
// --- VIKTIG ENDRING: HENT KORREKT VERDI ---
|
String value = "1";
|
||||||
// Gravity Forms sjekkbokser trenger verdien fra "choices" listen, ikke bare "1".
|
// Fallback
|
||||||
// F.eks: "Ja" hvis valget er "Ja".
|
|
||||||
String value = "1"; // Fallback
|
|
||||||
if (field.choices != null && i < field.choices.size()) {
|
if (field.choices != null && i < field.choices.size()) {
|
||||||
value = field.choices.get(i).value;
|
value = field.choices.get(i).value;
|
||||||
}
|
}
|
||||||
checkBox.setTag(value);
|
checkBox.setTag(value);
|
||||||
// -------------------------------------------
|
checkBox.setOnCheckedChangeListener((b, c) -> {
|
||||||
|
expandFormModule();
|
||||||
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
container.addView(checkBox);
|
container.addView(checkBox);
|
||||||
views.put(inputDef.id, checkBox);
|
views.put(inputDef.id, checkBox);
|
||||||
req.put(inputDef.id, false);
|
req.put(inputDef.id, false);
|
||||||
|
|
@ -776,6 +952,7 @@ public class FormsFragment extends Fragment {
|
||||||
dateInput.setClickable(true);
|
dateInput.setClickable(true);
|
||||||
dateInput.setHint("dd.mm.yyyy");
|
dateInput.setHint("dd.mm.yyyy");
|
||||||
dateInput.setOnClickListener(v -> {
|
dateInput.setOnClickListener(v -> {
|
||||||
|
expandFormModule(); // Trigger expand
|
||||||
Calendar c = Calendar.getInstance();
|
Calendar c = Calendar.getInstance();
|
||||||
new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
|
new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
|
||||||
dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
|
dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
|
||||||
|
|
@ -827,6 +1004,7 @@ public class FormsFragment extends Fragment {
|
||||||
else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
|
else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachInteractionListener(subInput);
|
||||||
container.addView(subInput);
|
container.addView(subInput);
|
||||||
views.put(subField.id, subInput);
|
views.put(subField.id, subInput);
|
||||||
req.put(subField.id, isSubRequired);
|
req.put(subField.id, isSubRequired);
|
||||||
|
|
@ -895,7 +1073,8 @@ public class FormsFragment extends Fragment {
|
||||||
aggregatedResult = aggregatedResult && ruleMatch;
|
aggregatedResult = aggregatedResult && ruleMatch;
|
||||||
if (!aggregatedResult) break;
|
if (!aggregatedResult) break;
|
||||||
} else {
|
} else {
|
||||||
aggregatedResult = aggregatedResult || ruleMatch;
|
aggregatedResult = aggregatedResult ||
|
||||||
|
ruleMatch;
|
||||||
if (aggregatedResult) break;
|
if (aggregatedResult) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -936,16 +1115,14 @@ public class FormsFragment extends Fragment {
|
||||||
Object item = ((Spinner) view).getSelectedItem();
|
Object item = ((Spinner) view).getSelectedItem();
|
||||||
return item != null ? item.toString() : "";
|
return item != null ? item.toString() : "";
|
||||||
}
|
}
|
||||||
// --- VIKTIG ENDRING: HENT TAG-VERDI ---
|
|
||||||
if (view instanceof CheckBox) {
|
if (view instanceof CheckBox) {
|
||||||
CheckBox cb = (CheckBox) view;
|
CheckBox cb = (CheckBox) view;
|
||||||
if (cb.isChecked()) {
|
if (cb.isChecked()) {
|
||||||
// Returner verdien lagret i Tag (f.eks "Ja") i stedet for hardkodet "1"
|
return cb.getTag() != null ?
|
||||||
return cb.getTag() != null ? cb.getTag().toString() : "1";
|
cb.getTag().toString() : "1";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
// ----------------------------------------
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -989,7 +1166,6 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
if (!val.isEmpty()) {
|
if (!val.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
// --- DATO FORMATERING FOR API (Fix 400 Bad Request) ---
|
|
||||||
GravityField fieldDef = getGravityFieldById(fieldId);
|
GravityField fieldDef = getGravityFieldById(fieldId);
|
||||||
if (fieldDef != null && "date".equals(fieldDef.type)) {
|
if (fieldDef != null && "date".equals(fieldDef.type)) {
|
||||||
val = formatDateForApi(val);
|
val = formatDateForApi(val);
|
||||||
|
|
@ -1035,10 +1211,9 @@ public class FormsFragment extends Fragment {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
// --- BEDRE LOGGING FOR 400 FEIL ---
|
|
||||||
String errBody = response.body() != null ? response.body().string() : "No body";
|
String errBody = response.body() != null ? response.body().string() : "No body";
|
||||||
Log.e(TAG, "Server error body: " + errBody);
|
Log.e(TAG, "Server error body: " + errBody);
|
||||||
updateStatus("Feil (" + response.code() + "): " + errBody); // Viser feilmeldingen i UI
|
updateStatus("Feil (" + response.code() + "): " + errBody);
|
||||||
} catch(Exception e){}
|
} catch(Exception e){}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1046,7 +1221,6 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Konverterer dd.MM.yyyy -> yyyy-MM-dd
|
|
||||||
private String formatDateForApi(String dateStr) {
|
private String formatDateForApi(String dateStr) {
|
||||||
if (dateStr == null || dateStr.isEmpty()) return "";
|
if (dateStr == null || dateStr.isEmpty()) return "";
|
||||||
try {
|
try {
|
||||||
|
|
@ -1055,7 +1229,7 @@ public class FormsFragment extends Fragment {
|
||||||
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||||
return apiFormat.format(date);
|
return apiFormat.format(date);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return dateStr; // Fallback hvis formatet er ukjent
|
return dateStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1110,13 +1284,16 @@ public class FormsFragment extends Fragment {
|
||||||
InputStream inputStream = getContext().getContentResolver().openInputStream(uri);
|
InputStream inputStream = getContext().getContentResolver().openInputStream(uri);
|
||||||
String fileName = getFileName(uri);
|
String fileName = getFileName(uri);
|
||||||
RequestBody requestBody = new RequestBody() {
|
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 {
|
@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);
|
return MultipartBody.Part.createFormData(partName, fileName, requestBody);
|
||||||
} catch (Exception e) { return null; }
|
} catch (Exception e) { return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchFormEntries() {
|
private void fetchFormEntries() {
|
||||||
|
|
@ -1151,7 +1328,8 @@ public class FormsFragment extends Fragment {
|
||||||
if (getActivity() != null) {
|
if (getActivity() != null) {
|
||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
showHistory(entries);
|
showHistory(entries);
|
||||||
if (formId == ID_ANSATTEOPPLYSNINGER && entries.length() > 0) {
|
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(); }
|
||||||
|
|
@ -1159,7 +1337,8 @@ public class FormsFragment extends Fragment {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (JSONException e) { e.printStackTrace(); }
|
} catch (JSONException e) { e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1177,14 +1356,21 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int count = Math.min(entries.length(), 5);
|
// Vis flere oppføringer siden vi nå har scrolle-mulighet øverst
|
||||||
|
int count = Math.min(entries.length(), 20);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
JSONObject entry = entries.getJSONObject(i);
|
JSONObject entry = entries.getJSONObject(i);
|
||||||
String date = entry.optString("date_created");
|
String date = entry.optString("date_created");
|
||||||
|
|
||||||
|
// Prøv å finne en bedre tittel enn bare dato (f.eks Prosjektnavn eller Sted)
|
||||||
|
String titleText = "Innsendt: " + date;
|
||||||
TextView item = new TextView(getContext());
|
TextView item = new TextView(getContext());
|
||||||
item.setText("Innsendt: " + date);
|
item.setText(titleText);
|
||||||
item.setPadding(10, 20, 10, 20);
|
item.setPadding(10, 20, 10, 20);
|
||||||
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
||||||
|
item.setTextSize(14);
|
||||||
|
// Add click listener to show details
|
||||||
|
item.setOnClickListener(v -> showEntryDetails(entry));
|
||||||
View line = new View(getContext());
|
View line = new View(getContext());
|
||||||
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||||
line.setBackgroundColor(Color.LTGRAY);
|
line.setBackgroundColor(Color.LTGRAY);
|
||||||
|
|
@ -1192,7 +1378,64 @@ public class FormsFragment extends Fragment {
|
||||||
historyContainer.addView(item);
|
historyContainer.addView(item);
|
||||||
historyContainer.addView(line);
|
historyContainer.addView(line);
|
||||||
}
|
}
|
||||||
} catch (JSONException e) { e.printStackTrace(); }
|
} catch (JSONException e) { e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NY METODE: Vis detaljer i dialog
|
||||||
|
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")
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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)";
|
||||||
|
}
|
||||||
|
|
||||||
|
details.append("<b>").append(field.label).append(":</b><br>")
|
||||||
|
.append(value).append("<br><br>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
details.append("Kunne ikke vise detaljer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView scroll = new ScrollView(getContext());
|
||||||
|
TextView text = new TextView(getContext());
|
||||||
|
text.setText(Html.fromHtml(details.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
text.setPadding(40, 40, 40, 40);
|
||||||
|
scroll.addView(text);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(getContext())
|
||||||
|
.setTitle("Detaljer")
|
||||||
|
.setView(scroll)
|
||||||
|
.setPositiveButton("Lukk", null)
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prefillFormFromHistory(JSONObject latestEntry) {
|
private void prefillFormFromHistory(JSONObject latestEntry) {
|
||||||
|
|
@ -1239,8 +1482,6 @@ public class FormsFragment extends Fragment {
|
||||||
} else if (view instanceof RadioGroup) {
|
} else if (view instanceof RadioGroup) {
|
||||||
((RadioGroup) view).clearCheck();
|
((RadioGroup) view).clearCheck();
|
||||||
} else if (view instanceof Button) {
|
} else if (view instanceof Button) {
|
||||||
// Fix: CheckBox inherits from Button, so we must be careful.
|
|
||||||
// Only cast to TextView if the tag is actually a TextView (File Upload logic)
|
|
||||||
Object tag = view.getTag();
|
Object tag = view.getTag();
|
||||||
if (tag instanceof TextView) {
|
if (tag instanceof TextView) {
|
||||||
((TextView) tag).setText("Ingen fil valgt");
|
((TextView) tag).setText("Ingen fil valgt");
|
||||||
|
|
@ -1253,12 +1494,12 @@ public class FormsFragment extends Fragment {
|
||||||
if (totalAmountView != null) totalAmountView.setText("Kr 0,00");
|
if (totalAmountView != null) totalAmountView.setText("Kr 0,00");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- HJELPEKLASSE FOR NESTED ENTRIES ---
|
|
||||||
private static class NestedEntry {
|
private static class NestedEntry {
|
||||||
String id;
|
String id;
|
||||||
String description;
|
String description;
|
||||||
String price;
|
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) {
|
private void updateStatus(String msg) {
|
||||||
|
|
|
||||||
|
|
@ -2,194 +2,60 @@ package com.kbs.kbsintranett;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
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.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
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.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
public class FormsListFragment extends Fragment {
|
public class FormsListFragment extends Fragment {
|
||||||
|
|
||||||
private static final String TAG = "FormsListFragment";
|
|
||||||
private LinearLayout container;
|
|
||||||
private ProgressBar loadingSpinner;
|
|
||||||
private TextView txtStatus;
|
|
||||||
|
|
||||||
// Regex for å finne tall i starten av tittelen (f.eks "10. Tittel")
|
|
||||||
// Group 1 = Tallet
|
|
||||||
// Group 2 = Resten av teksten (den rene tittelen)
|
|
||||||
private static final Pattern TITLE_PATTERN = Pattern.compile("^(\\d+)[.\\s-]+\\s*(.*)");
|
|
||||||
|
|
||||||
@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_list, container, false);
|
||||||
this.container = view.findViewById(R.id.form_container);
|
LinearLayout formsContainer = view.findViewById(R.id.forms_container);
|
||||||
this.loadingSpinner = view.findViewById(R.id.loading_spinner);
|
|
||||||
this.txtStatus = view.findViewById(R.id.txt_status);
|
|
||||||
|
|
||||||
View historyTitle = view.findViewById(R.id.historyContainer);
|
// Legger til knappene for de ulike skjemaene
|
||||||
if (historyTitle != null) historyTitle.setVisibility(View.GONE);
|
addFormButton(formsContainer, "1. Ansatteopplysninger", 1);
|
||||||
|
addFormButton(formsContainer, "4. RUH (Rapport om uønsket hendelse)", 4);
|
||||||
LinearLayout mainLayout = view.findViewById(R.id.main_layout);
|
addFormButton(formsContainer, "9. Sikkerhetskurs / Kompetansebevis", 9);
|
||||||
if (mainLayout != null && mainLayout.getChildCount() > 4) {
|
addFormButton(formsContainer, "10. HMS-bekreftelse", 10);
|
||||||
for(int i = 0; i < mainLayout.getChildCount(); i++) {
|
addFormButton(formsContainer, "11. Egenmelding", 11);
|
||||||
View child = mainLayout.getChildAt(i);
|
addFormButton(formsContainer, "12. Sjekkliste for firmabil", 12);
|
||||||
if (child instanceof TextView && ((TextView)child).getText().toString().contains("Tidligere")) {
|
addFormButton(formsContainer, "14. SJA (Sikker Jobbanalyse)", 14);
|
||||||
child.setVisibility(View.GONE);
|
addFormButton(formsContainer, "15. Fraværsvarsel", 15);
|
||||||
}
|
addFormButton(formsContainer, "16. Refusjon utlegg", 16);
|
||||||
}
|
addFormButton(formsContainer, "21. Forberedelse til medarbeidersamtale", 21);
|
||||||
}
|
addFormButton(formsContainer, "22. Medarbeiderundersøkelse", 22);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void addFormButton(LinearLayout container, String title, int formId) {
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
Button btn = new Button(getContext());
|
||||||
super.onViewCreated(view, savedInstanceState);
|
btn.setText(title);
|
||||||
fetchFormsList();
|
btn.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||||
}
|
btn.setTextColor(Color.WHITE);
|
||||||
|
btn.setPadding(30, 30, 30, 30);
|
||||||
private void fetchFormsList() {
|
|
||||||
if (container != null) container.removeAllViews();
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
|
||||||
if (txtStatus != null) txtStatus.setText("");
|
|
||||||
|
|
||||||
// Vi bruker standard-kallet som er raskt og effektivt
|
|
||||||
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
|
||||||
Map<String, GravityForm> formMap = response.body();
|
|
||||||
|
|
||||||
if (formMap.isEmpty()) {
|
|
||||||
if (txtStatus != null) txtStatus.setText("Ingen skjemaer funnet.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GravityForm> visibleForms = new ArrayList<>();
|
|
||||||
for (GravityForm form : formMap.values()) {
|
|
||||||
// Sjekk om aktiv
|
|
||||||
boolean isActive = form.isActive == null || !"0".equals(form.isActive);
|
|
||||||
|
|
||||||
// Sjekk om vi finner et sorteringstall i tittelen
|
|
||||||
Integer sortOrder = getSortOrderFromTitle(form.title);
|
|
||||||
|
|
||||||
if (form != null && form.title != null && isActive && sortOrder != null) {
|
|
||||||
visibleForms.add(form);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (visibleForms.isEmpty()) {
|
|
||||||
if (txtStatus != null) txtStatus.setText("Ingen tilgjengelige skjemaer (sjekk nummerering i titler).");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sorter listen basert på tallet i tittelen
|
|
||||||
Collections.sort(visibleForms, new Comparator<GravityForm>() {
|
|
||||||
@Override
|
|
||||||
public int compare(GravityForm f1, GravityForm f2) {
|
|
||||||
return Integer.compare(getSortOrderFromTitle(f1.title), getSortOrderFromTitle(f2.title));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (GravityForm form : visibleForms) {
|
|
||||||
addFormButton(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (txtStatus != null) txtStatus.setText("Kunne ikke laste listen (Kode " + response.code() + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
|
||||||
if (txtStatus != null) txtStatus.setText("Nettverksfeil: " + t.getMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Henter ut tallet fra starten av tittelen.
|
|
||||||
* Returnerer null hvis tittelen ikke starter med et tall.
|
|
||||||
*/
|
|
||||||
private Integer getSortOrderFromTitle(String title) {
|
|
||||||
if (title == null) return null;
|
|
||||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
|
||||||
if (m.find()) {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(m.group(1));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null; // Ingen tall funnet -> Skjules
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Henter ut selve navnet på skjemaet (uten tallet foran).
|
|
||||||
* "10. Ansatte" -> "Ansatte"
|
|
||||||
*/
|
|
||||||
private String getCleanTitle(String title) {
|
|
||||||
if (title == null) return "";
|
|
||||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
|
||||||
if (m.find()) {
|
|
||||||
// Group 2 er resten av teksten etter tallet og punktum/mellomrom
|
|
||||||
return m.group(2);
|
|
||||||
}
|
|
||||||
return title; // Fallback hvis regex ikke matcher (skal ikke skje pga filtreringen over)
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFormButton(GravityForm form) {
|
|
||||||
Button button = new Button(getContext());
|
|
||||||
|
|
||||||
// VIS VASKET TITTEL PÅ KNAPPEN
|
|
||||||
String displayTitle = getCleanTitle(form.title);
|
|
||||||
button.setText(displayTitle.toUpperCase());
|
|
||||||
|
|
||||||
button.setTextColor(Color.WHITE);
|
|
||||||
button.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
|
||||||
button.setTextSize(14);
|
|
||||||
button.setPadding(30, 30, 30, 30);
|
|
||||||
|
|
||||||
button.setOnClickListener(v -> {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putInt("formId", form.id);
|
|
||||||
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
|
||||||
});
|
|
||||||
|
|
||||||
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); // Litt avstand mellom knappene
|
||||||
params.setMargins(0, 0, 0, 20);
|
btn.setLayoutParams(params);
|
||||||
button.setLayoutParams(params);
|
|
||||||
|
|
||||||
container.addView(button);
|
btn.setOnClickListener(v -> {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt("formId", formId);
|
||||||
|
// HER VAR FEILEN: Endret R.id.nav_forms til riktig action ID
|
||||||
|
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addView(btn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,74 +1,104 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<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_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="16dp"
|
android:orientation="vertical"
|
||||||
android:background="@android:color/white">
|
android:background="#F5F5F5"
|
||||||
|
tools:context=".FormsFragment">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/main_layout"
|
android:id="@+id/history_wrapper"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:orientation="vertical">
|
android:layout_weight="3"
|
||||||
|
android:orientation="vertical"
|
||||||
<TextView
|
android:background="#FFFFFF"
|
||||||
android:layout_width="wrap_content"
|
android:elevation="4dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginBottom="8dp"
|
||||||
android:text="Skjema"
|
android:padding="16dp">
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:layout_marginBottom="16dp"/>
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/loading_spinner"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:visibility="visible" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/lbl_history"
|
android:id="@+id/lbl_history"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Tidligere innsendinger:"
|
android:text="Tidligere innsendinger"
|
||||||
android:textStyle="bold"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:layout_marginBottom="5dp"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/historyContainer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginBottom="20dp"/>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="2dp"
|
|
||||||
android:background="#0069B3"
|
|
||||||
android:layout_marginBottom="20dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Ny innsending:"
|
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:textColor="#333333"
|
||||||
android:layout_marginBottom="10dp"/>
|
android:layout_marginBottom="10dp"/>
|
||||||
|
|
||||||
<LinearLayout
|
<ScrollView
|
||||||
android:id="@+id/form_container"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_status"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:textColor="#D32F2F"
|
|
||||||
android:gravity="center" />
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/historyContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="7"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="#FFFFFF"
|
||||||
|
android:elevation="4dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="#FAFAFA">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/loading_spinner"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginEnd="8dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/txt_status"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textColor="#666666"
|
||||||
|
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
|
||||||
|
android:id="@+id/form_scroll_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/form_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="40dp">
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
30
app/src/main/res/layout/fragment_forms_list.xml
Normal file
30
app/src/main/res/layout/fragment_forms_list.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/main_layout" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="#F5F5F5">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/header_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Skjemaer"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:textColor="#333333"/>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/forms_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
4
app/src/main/res/xml/file_paths.xml
Normal file
4
app/src/main/res/xml/file_paths.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<external-files-path name="my_images" path="Pictures" />
|
||||||
|
</paths>
|
||||||
|
|
@ -198,6 +198,17 @@ FILSTI: app\src\main\AndroidManifest.xml
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="com.kbs.kbsintranett.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
@ -437,16 +448,20 @@ FILSTI: app\src\main\java\com\kbs\kbsintranett\FormsFragment.java
|
||||||
============================================================
|
============================================================
|
||||||
package com.kbs.kbsintranett;
|
package com.kbs.kbsintranett;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.animation.LayoutTransition;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.DatePickerDialog;
|
import android.app.DatePickerDialog;
|
||||||
import android.app.TimePickerDialog;
|
import android.app.TimePickerDialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
|
|
@ -455,6 +470,7 @@ import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
|
|
@ -474,6 +490,8 @@ import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.content.FileProvider;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
|
@ -483,6 +501,7 @@ import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
@ -529,6 +548,7 @@ public class FormsFragment extends Fragment {
|
||||||
|
|
||||||
private LinearLayout formContainer;
|
private LinearLayout formContainer;
|
||||||
private LinearLayout historyContainer;
|
private LinearLayout historyContainer;
|
||||||
|
private View historyWrapper; // Wrapper for historikk-modulen som skal skjules
|
||||||
private TextView txtStatus;
|
private TextView txtStatus;
|
||||||
private TextView lblHistory;
|
private TextView lblHistory;
|
||||||
private ProgressBar loadingSpinner;
|
private ProgressBar loadingSpinner;
|
||||||
|
|
@ -547,9 +567,15 @@ public class FormsFragment extends Fragment {
|
||||||
private List<NestedEntry> nestedEntries = new ArrayList<>();
|
private List<NestedEntry> nestedEntries = new ArrayList<>();
|
||||||
private LinearLayout nestedEntriesContainer;
|
private LinearLayout nestedEntriesContainer;
|
||||||
private TextView totalAmountView;
|
private TextView totalAmountView;
|
||||||
|
|
||||||
|
// --- FILOPPLASTING & KAMERA ---
|
||||||
private String pendingFileFieldId = null;
|
private String pendingFileFieldId = null;
|
||||||
private boolean isSelectingForChild = false;
|
private boolean isSelectingForChild = false;
|
||||||
|
private Uri currentPhotoUri = null;
|
||||||
|
|
||||||
private ActivityResultLauncher<Intent> filePickerLauncher;
|
private ActivityResultLauncher<Intent> filePickerLauncher;
|
||||||
|
private ActivityResultLauncher<Uri> takePictureLauncher;
|
||||||
|
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||||
|
|
||||||
private GravityForm currentForm;
|
private GravityForm currentForm;
|
||||||
private final OkHttpClient client = new OkHttpClient();
|
private final OkHttpClient client = new OkHttpClient();
|
||||||
|
|
@ -559,6 +585,7 @@ public class FormsFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
filePickerLauncher = registerForActivityResult(
|
filePickerLauncher = registerForActivityResult(
|
||||||
new ActivityResultContracts.StartActivityForResult(),
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
result -> {
|
result -> {
|
||||||
|
|
@ -568,8 +595,28 @@ public class FormsFragment extends Fragment {
|
||||||
handleFileSelection(pendingFileFieldId, uri, isSelectingForChild);
|
handleFileSelection(pendingFileFieldId, uri, isSelectingForChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pendingFileFieldId = null;
|
}
|
||||||
isSelectingForChild = false;
|
);
|
||||||
|
|
||||||
|
takePictureLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.TakePicture(),
|
||||||
|
success -> {
|
||||||
|
if (success && currentPhotoUri != null && pendingFileFieldId != null) {
|
||||||
|
handleFileSelection(pendingFileFieldId, currentPhotoUri, isSelectingForChild);
|
||||||
|
} else if (!success) {
|
||||||
|
currentPhotoUri = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
requestPermissionLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.RequestPermission(),
|
||||||
|
isGranted -> {
|
||||||
|
if (isGranted) {
|
||||||
|
openCamera();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Kameratillatelse er påkrevd for å ta bilde.", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -578,12 +625,26 @@ public class FormsFragment extends Fragment {
|
||||||
@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);
|
||||||
|
historyWrapper = view.findViewById(R.id.history_wrapper); // Ny referanse
|
||||||
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);
|
||||||
|
|
||||||
|
// --- FIKS FOR NULLPOINTER EXCEPTION ---
|
||||||
|
// Vi sjekker om LayoutTransition finnes, hvis ikke lager vi en ny.
|
||||||
|
if (view instanceof ViewGroup) {
|
||||||
|
LayoutTransition transition = ((ViewGroup) view).getLayoutTransition();
|
||||||
|
if (transition == null) {
|
||||||
|
transition = new LayoutTransition();
|
||||||
|
((ViewGroup) view).setLayoutTransition(transition);
|
||||||
|
}
|
||||||
|
transition.enableTransitionType(LayoutTransition.CHANGING);
|
||||||
|
}
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
if (formContainer == null) {
|
if (formContainer == null) {
|
||||||
formContainer = new LinearLayout(getContext());
|
formContainer = new LinearLayout(getContext());
|
||||||
}
|
}
|
||||||
|
|
@ -598,6 +659,41 @@ public class FormsFragment extends Fragment {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
// Focus listener for edittexts etc
|
||||||
|
view.setOnFocusChangeListener((v, hasFocus) -> {
|
||||||
|
if (hasFocus) {
|
||||||
|
expandFormModule();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click listener for buttons/checkboxes
|
||||||
|
if (view.isClickable()) {
|
||||||
|
view.setOnClickListener(v -> expandFormModule());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
private void fetchFormStructure() {
|
private void fetchFormStructure() {
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
||||||
updateStatus("Laster skjema...");
|
updateStatus("Laster skjema...");
|
||||||
|
|
@ -639,6 +735,9 @@ public class FormsFragment extends Fragment {
|
||||||
nestedEntries.clear();
|
nestedEntries.clear();
|
||||||
updateStatus("");
|
updateStatus("");
|
||||||
|
|
||||||
|
// Reset visibility of history on new load
|
||||||
|
if (historyWrapper != null) historyWrapper.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
TextView title = new TextView(getContext());
|
TextView title = new TextView(getContext());
|
||||||
title.setText(getCleanTitle(form.title));
|
title.setText(getCleanTitle(form.title));
|
||||||
title.setTextSize(24);
|
title.setTextSize(24);
|
||||||
|
|
@ -763,6 +862,7 @@ public class FormsFragment extends Fragment {
|
||||||
btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
|
btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
|
||||||
btnAdd.setTextColor(Color.WHITE);
|
btnAdd.setTextColor(Color.WHITE);
|
||||||
btnAdd.setOnClickListener(v -> {
|
btnAdd.setOnClickListener(v -> {
|
||||||
|
expandFormModule(); // Trigger expand
|
||||||
int childFormId = 18;
|
int childFormId = 18;
|
||||||
if (field.gpnfForm != null) {
|
if (field.gpnfForm != null) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -817,7 +917,6 @@ public class FormsFragment extends Fragment {
|
||||||
|
|
||||||
private void showChildFormDialog(GravityForm childForm) {
|
private void showChildFormDialog(GravityForm childForm) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||||
// FJERNET: builder.setTitle(childForm.title); - Brukeren ønsket ikke tittel i popup
|
|
||||||
|
|
||||||
childInputViews.clear();
|
childInputViews.clear();
|
||||||
childRequiredFieldsMap.clear();
|
childRequiredFieldsMap.clear();
|
||||||
|
|
@ -979,27 +1078,20 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FELLES METODER ---
|
// --- FELLES METODER (FILE UPLOAD M/ CAMERA STØTTE) ---
|
||||||
|
|
||||||
private void renderFileUploadField(LinearLayout container, GravityField field, Map<String, View> viewsMap, Map<String, Boolean> reqMap, boolean isChild) {
|
private void renderFileUploadField(LinearLayout container, GravityField field, Map<String, View> viewsMap, Map<String, Boolean> reqMap, boolean isChild) {
|
||||||
LinearLayout fileLayout = new LinearLayout(getContext());
|
LinearLayout fileLayout = new LinearLayout(getContext());
|
||||||
fileLayout.setOrientation(LinearLayout.HORIZONTAL);
|
fileLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
Button btnUpload = new Button(getContext());
|
Button btnUpload = new Button(getContext());
|
||||||
btnUpload.setText("Velg fil");
|
btnUpload.setText("Velg fil / Ta bilde");
|
||||||
btnUpload.setOnClickListener(v -> {
|
btnUpload.setOnClickListener(v -> {
|
||||||
if (filePickerLauncher == null) return;
|
// Setter state før vi viser dialog
|
||||||
try {
|
pendingFileFieldId = field.id;
|
||||||
pendingFileFieldId = field.id;
|
isSelectingForChild = isChild;
|
||||||
isSelectingForChild = isChild;
|
expandFormModule(); // Trigger expand
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
showFileSourceDialog();
|
||||||
intent.setType("*/*");
|
|
||||||
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
|
||||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
|
||||||
filePickerLauncher.launch(intent);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
TextView txtFileName = new TextView(getContext());
|
TextView txtFileName = new TextView(getContext());
|
||||||
txtFileName.setText("Ingen fil valgt");
|
txtFileName.setText("Ingen fil valgt");
|
||||||
|
|
@ -1015,6 +1107,63 @@ public class FormsFragment extends Fragment {
|
||||||
reqMap.put(field.id, field.isRequired);
|
reqMap.put(field.id, field.isRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hjelpemetode for å vise dialog
|
||||||
|
private void showFileSourceDialog() {
|
||||||
|
String[] options = {"Ta bilde", "Velg fil"};
|
||||||
|
new AlertDialog.Builder(getContext())
|
||||||
|
.setTitle("Last opp vedlegg")
|
||||||
|
.setItems(options, (dialog, which) -> {
|
||||||
|
if (which == 0) {
|
||||||
|
// Ta bilde - SJEKKER PERMISSION FØRST
|
||||||
|
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
|
||||||
|
== PackageManager.PERMISSION_GRANTED) {
|
||||||
|
openCamera();
|
||||||
|
} else {
|
||||||
|
// Spør om lov
|
||||||
|
requestPermissionLauncher.launch(Manifest.permission.CAMERA);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Velg fil
|
||||||
|
if (filePickerLauncher != null) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
intent.setType("*/*");
|
||||||
|
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
||||||
|
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||||
|
filePickerLauncher.launch(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openCamera() {
|
||||||
|
currentPhotoUri = createImageUri();
|
||||||
|
if (currentPhotoUri != null && takePictureLauncher != null) {
|
||||||
|
try {
|
||||||
|
takePictureLauncher.launch(currentPhotoUri);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(getContext(), "Kunne ikke starte kamera: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
Log.e(TAG, "Camera launch failed", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Kunne ikke opprette bildefil", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Uri createImageUri() {
|
||||||
|
try {
|
||||||
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||||
|
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();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
|
private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
|
||||||
if (isChild) {
|
if (isChild) {
|
||||||
childFileUploads.put(fieldId, uri);
|
childFileUploads.put(fieldId, uri);
|
||||||
|
|
@ -1068,6 +1217,7 @@ public class FormsFragment extends Fragment {
|
||||||
timeInput.setClickable(true);
|
timeInput.setClickable(true);
|
||||||
timeInput.setHint("00:00");
|
timeInput.setHint("00:00");
|
||||||
timeInput.setOnClickListener(v -> {
|
timeInput.setOnClickListener(v -> {
|
||||||
|
expandFormModule(); // Trigger expand
|
||||||
Calendar mcurrentTime = Calendar.getInstance();
|
Calendar mcurrentTime = Calendar.getInstance();
|
||||||
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
||||||
int minute = mcurrentTime.get(Calendar.MINUTE);
|
int minute = mcurrentTime.get(Calendar.MINUTE);
|
||||||
|
|
@ -1108,6 +1258,9 @@ public class FormsFragment extends Fragment {
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||||
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
|
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
attachInteractionListener(input); // Add listener
|
||||||
|
|
||||||
container.addView(input);
|
container.addView(input);
|
||||||
views.put(field.id, input);
|
views.put(field.id, input);
|
||||||
req.put(field.id, field.isRequired);
|
req.put(field.id, field.isRequired);
|
||||||
|
|
@ -1119,6 +1272,9 @@ public class FormsFragment extends Fragment {
|
||||||
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||||
input.setMinLines(3);
|
input.setMinLines(3);
|
||||||
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
|
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
|
||||||
|
|
||||||
|
attachInteractionListener(input); // Add listener
|
||||||
|
|
||||||
container.addView(input);
|
container.addView(input);
|
||||||
views.put(field.id, input);
|
views.put(field.id, input);
|
||||||
req.put(field.id, field.isRequired);
|
req.put(field.id, field.isRequired);
|
||||||
|
|
@ -1131,10 +1287,20 @@ public class FormsFragment extends Fragment {
|
||||||
RadioButton rb = new RadioButton(getContext());
|
RadioButton rb = new RadioButton(getContext());
|
||||||
rb.setText(choice.text);
|
rb.setText(choice.text);
|
||||||
rb.setTag(choice.value);
|
rb.setTag(choice.value);
|
||||||
|
// Also trigger expand on RadioButton click
|
||||||
|
rb.setOnClickListener(v -> {
|
||||||
|
expandFormModule();
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
group.addView(rb);
|
group.addView(rb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group.setOnCheckedChangeListener((g, i) -> evaluateAllConditionalLogic());
|
// Fallback listener
|
||||||
|
group.setOnCheckedChangeListener((g, i) -> {
|
||||||
|
expandFormModule();
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
|
|
||||||
container.addView(group);
|
container.addView(group);
|
||||||
views.put(field.id, group);
|
views.put(field.id, group);
|
||||||
req.put(field.id, field.isRequired);
|
req.put(field.id, field.isRequired);
|
||||||
|
|
@ -1142,6 +1308,14 @@ public class FormsFragment extends Fragment {
|
||||||
|
|
||||||
private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
|
private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
|
||||||
Spinner spinner = new Spinner(getContext());
|
Spinner spinner = new Spinner(getContext());
|
||||||
|
// Spinner touch listener is tricky, usually set onTouchListener works
|
||||||
|
spinner.setOnTouchListener((v, event) -> {
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||||
|
expandFormModule();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
List<String> labels = new ArrayList<>();
|
List<String> labels = new ArrayList<>();
|
||||||
labels.add("- Velg -");
|
labels.add("- Velg -");
|
||||||
if (field.choices != null) {
|
if (field.choices != null) {
|
||||||
|
|
@ -1160,10 +1334,13 @@ public class FormsFragment extends Fragment {
|
||||||
checkBox.setText(cbText);
|
checkBox.setText(cbText);
|
||||||
String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
|
String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
|
||||||
|
|
||||||
// For Consent fields, Gravity Forms typically expects "1" if checked.
|
|
||||||
checkBox.setTag("1");
|
checkBox.setTag("1");
|
||||||
|
|
||||||
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
|
checkBox.setOnCheckedChangeListener((b, c) -> {
|
||||||
|
expandFormModule();
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
|
|
||||||
container.addView(checkBox);
|
container.addView(checkBox);
|
||||||
views.put(inputId, checkBox);
|
views.put(inputId, checkBox);
|
||||||
req.put(inputId, field.isRequired);
|
req.put(inputId, field.isRequired);
|
||||||
|
|
@ -1176,17 +1353,16 @@ public class FormsFragment extends Fragment {
|
||||||
CheckBox checkBox = new CheckBox(getContext());
|
CheckBox checkBox = new CheckBox(getContext());
|
||||||
checkBox.setText(inputDef.label);
|
checkBox.setText(inputDef.label);
|
||||||
|
|
||||||
// --- VIKTIG ENDRING: HENT KORREKT VERDI ---
|
|
||||||
// Gravity Forms sjekkbokser trenger verdien fra "choices" listen, ikke bare "1".
|
|
||||||
// F.eks: "Ja" hvis valget er "Ja".
|
|
||||||
String value = "1"; // Fallback
|
String value = "1"; // Fallback
|
||||||
if (field.choices != null && i < field.choices.size()) {
|
if (field.choices != null && i < field.choices.size()) {
|
||||||
value = field.choices.get(i).value;
|
value = field.choices.get(i).value;
|
||||||
}
|
}
|
||||||
checkBox.setTag(value);
|
checkBox.setTag(value);
|
||||||
// -------------------------------------------
|
|
||||||
|
|
||||||
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
|
checkBox.setOnCheckedChangeListener((b, c) -> {
|
||||||
|
expandFormModule();
|
||||||
|
evaluateAllConditionalLogic();
|
||||||
|
});
|
||||||
container.addView(checkBox);
|
container.addView(checkBox);
|
||||||
views.put(inputDef.id, checkBox);
|
views.put(inputDef.id, checkBox);
|
||||||
req.put(inputDef.id, false);
|
req.put(inputDef.id, false);
|
||||||
|
|
@ -1213,6 +1389,7 @@ public class FormsFragment extends Fragment {
|
||||||
dateInput.setClickable(true);
|
dateInput.setClickable(true);
|
||||||
dateInput.setHint("dd.mm.yyyy");
|
dateInput.setHint("dd.mm.yyyy");
|
||||||
dateInput.setOnClickListener(v -> {
|
dateInput.setOnClickListener(v -> {
|
||||||
|
expandFormModule(); // Trigger expand
|
||||||
Calendar c = Calendar.getInstance();
|
Calendar c = Calendar.getInstance();
|
||||||
new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
|
new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
|
||||||
dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
|
dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
|
||||||
|
|
@ -1264,6 +1441,8 @@ public class FormsFragment extends Fragment {
|
||||||
else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
|
else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachInteractionListener(subInput);
|
||||||
|
|
||||||
container.addView(subInput);
|
container.addView(subInput);
|
||||||
views.put(subField.id, subInput);
|
views.put(subField.id, subInput);
|
||||||
req.put(subField.id, isSubRequired);
|
req.put(subField.id, isSubRequired);
|
||||||
|
|
@ -1373,16 +1552,13 @@ public class FormsFragment extends Fragment {
|
||||||
Object item = ((Spinner) view).getSelectedItem();
|
Object item = ((Spinner) view).getSelectedItem();
|
||||||
return item != null ? item.toString() : "";
|
return item != null ? item.toString() : "";
|
||||||
}
|
}
|
||||||
// --- VIKTIG ENDRING: HENT TAG-VERDI ---
|
|
||||||
if (view instanceof CheckBox) {
|
if (view instanceof CheckBox) {
|
||||||
CheckBox cb = (CheckBox) view;
|
CheckBox cb = (CheckBox) view;
|
||||||
if (cb.isChecked()) {
|
if (cb.isChecked()) {
|
||||||
// Returner verdien lagret i Tag (f.eks "Ja") i stedet for hardkodet "1"
|
|
||||||
return cb.getTag() != null ? cb.getTag().toString() : "1";
|
return cb.getTag() != null ? cb.getTag().toString() : "1";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
// ----------------------------------------
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1426,7 +1602,6 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
if (!val.isEmpty()) {
|
if (!val.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
// --- DATO FORMATERING FOR API (Fix 400 Bad Request) ---
|
|
||||||
GravityField fieldDef = getGravityFieldById(fieldId);
|
GravityField fieldDef = getGravityFieldById(fieldId);
|
||||||
if (fieldDef != null && "date".equals(fieldDef.type)) {
|
if (fieldDef != null && "date".equals(fieldDef.type)) {
|
||||||
val = formatDateForApi(val);
|
val = formatDateForApi(val);
|
||||||
|
|
@ -1472,10 +1647,9 @@ public class FormsFragment extends Fragment {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
// --- BEDRE LOGGING FOR 400 FEIL ---
|
|
||||||
String errBody = response.body() != null ? response.body().string() : "No body";
|
String errBody = response.body() != null ? response.body().string() : "No body";
|
||||||
Log.e(TAG, "Server error body: " + errBody);
|
Log.e(TAG, "Server error body: " + errBody);
|
||||||
updateStatus("Feil (" + response.code() + "): " + errBody); // Viser feilmeldingen i UI
|
updateStatus("Feil (" + response.code() + "): " + errBody);
|
||||||
} catch(Exception e){}
|
} catch(Exception e){}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1483,7 +1657,6 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Konverterer dd.MM.yyyy -> yyyy-MM-dd
|
|
||||||
private String formatDateForApi(String dateStr) {
|
private String formatDateForApi(String dateStr) {
|
||||||
if (dateStr == null || dateStr.isEmpty()) return "";
|
if (dateStr == null || dateStr.isEmpty()) return "";
|
||||||
try {
|
try {
|
||||||
|
|
@ -1492,7 +1665,7 @@ public class FormsFragment extends Fragment {
|
||||||
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||||
return apiFormat.format(date);
|
return apiFormat.format(date);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return dateStr; // Fallback hvis formatet er ukjent
|
return dateStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1614,14 +1787,24 @@ public class FormsFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int count = Math.min(entries.length(), 5);
|
// Vis flere oppføringer siden vi nå har scrolle-mulighet øverst
|
||||||
|
int count = Math.min(entries.length(), 20);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
JSONObject entry = entries.getJSONObject(i);
|
JSONObject entry = entries.getJSONObject(i);
|
||||||
String date = entry.optString("date_created");
|
String date = entry.optString("date_created");
|
||||||
|
|
||||||
|
// Prøv å finne en bedre tittel enn bare dato (f.eks Prosjektnavn eller Sted)
|
||||||
|
String titleText = "Innsendt: " + date;
|
||||||
|
|
||||||
TextView item = new TextView(getContext());
|
TextView item = new TextView(getContext());
|
||||||
item.setText("Innsendt: " + date);
|
item.setText(titleText);
|
||||||
item.setPadding(10, 20, 10, 20);
|
item.setPadding(10, 20, 10, 20);
|
||||||
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
||||||
|
item.setTextSize(14);
|
||||||
|
|
||||||
|
// Add click listener to show details
|
||||||
|
item.setOnClickListener(v -> showEntryDetails(entry));
|
||||||
|
|
||||||
View line = new View(getContext());
|
View line = new View(getContext());
|
||||||
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||||
line.setBackgroundColor(Color.LTGRAY);
|
line.setBackgroundColor(Color.LTGRAY);
|
||||||
|
|
@ -1632,6 +1815,64 @@ public class FormsFragment extends Fragment {
|
||||||
} catch (JSONException e) { e.printStackTrace(); }
|
} catch (JSONException e) { e.printStackTrace(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NY METODE: Vis detaljer i dialog
|
||||||
|
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")
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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)";
|
||||||
|
}
|
||||||
|
|
||||||
|
details.append("<b>").append(field.label).append(":</b><br>")
|
||||||
|
.append(value).append("<br><br>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
details.append("Kunne ikke vise detaljer.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView scroll = new ScrollView(getContext());
|
||||||
|
TextView text = new TextView(getContext());
|
||||||
|
text.setText(Html.fromHtml(details.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||||
|
text.setPadding(40, 40, 40, 40);
|
||||||
|
scroll.addView(text);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(getContext())
|
||||||
|
.setTitle("Detaljer")
|
||||||
|
.setView(scroll)
|
||||||
|
.setPositiveButton("Lukk", null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
private void prefillFormFromHistory(JSONObject latestEntry) {
|
private void prefillFormFromHistory(JSONObject latestEntry) {
|
||||||
if (latestEntry == null) return;
|
if (latestEntry == null) return;
|
||||||
for (Map.Entry<String, View> entry : inputViews.entrySet()) {
|
for (Map.Entry<String, View> entry : inputViews.entrySet()) {
|
||||||
|
|
@ -1676,8 +1917,6 @@ public class FormsFragment extends Fragment {
|
||||||
} else if (view instanceof RadioGroup) {
|
} else if (view instanceof RadioGroup) {
|
||||||
((RadioGroup) view).clearCheck();
|
((RadioGroup) view).clearCheck();
|
||||||
} else if (view instanceof Button) {
|
} else if (view instanceof Button) {
|
||||||
// Fix: CheckBox inherits from Button, so we must be careful.
|
|
||||||
// Only cast to TextView if the tag is actually a TextView (File Upload logic)
|
|
||||||
Object tag = view.getTag();
|
Object tag = view.getTag();
|
||||||
if (tag instanceof TextView) {
|
if (tag instanceof TextView) {
|
||||||
((TextView) tag).setText("Ingen fil valgt");
|
((TextView) tag).setText("Ingen fil valgt");
|
||||||
|
|
@ -1690,7 +1929,6 @@ public class FormsFragment extends Fragment {
|
||||||
if (totalAmountView != null) totalAmountView.setText("Kr 0,00");
|
if (totalAmountView != null) totalAmountView.setText("Kr 0,00");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- HJELPEKLASSE FOR NESTED ENTRIES ---
|
|
||||||
private static class NestedEntry {
|
private static class NestedEntry {
|
||||||
String id;
|
String id;
|
||||||
String description;
|
String description;
|
||||||
|
|
@ -1712,195 +1950,59 @@ package com.kbs.kbsintranett;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
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.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
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.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
public class FormsListFragment extends Fragment {
|
public class FormsListFragment extends Fragment {
|
||||||
|
|
||||||
private static final String TAG = "FormsListFragment";
|
|
||||||
private LinearLayout container;
|
|
||||||
private ProgressBar loadingSpinner;
|
|
||||||
private TextView txtStatus;
|
|
||||||
|
|
||||||
// Regex for å finne tall i starten av tittelen (f.eks "10. Tittel")
|
|
||||||
// Group 1 = Tallet
|
|
||||||
// Group 2 = Resten av teksten (den rene tittelen)
|
|
||||||
private static final Pattern TITLE_PATTERN = Pattern.compile("^(\\d+)[.\\s-]+\\s*(.*)");
|
|
||||||
|
|
||||||
@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_list, container, false);
|
||||||
this.container = view.findViewById(R.id.form_container);
|
LinearLayout formsContainer = view.findViewById(R.id.forms_container);
|
||||||
this.loadingSpinner = view.findViewById(R.id.loading_spinner);
|
|
||||||
this.txtStatus = view.findViewById(R.id.txt_status);
|
|
||||||
|
|
||||||
View historyTitle = view.findViewById(R.id.historyContainer);
|
addFormButton(formsContainer, "1. Ansatteopplysninger", 1);
|
||||||
if (historyTitle != null) historyTitle.setVisibility(View.GONE);
|
addFormButton(formsContainer, "4. RUH (Rapport om uønsket hendelse)", 4);
|
||||||
|
addFormButton(formsContainer, "9. Sikkerhetskurs / Kompetansebevis", 9);
|
||||||
LinearLayout mainLayout = view.findViewById(R.id.main_layout);
|
addFormButton(formsContainer, "10. HMS-bekreftelse", 10);
|
||||||
if (mainLayout != null && mainLayout.getChildCount() > 4) {
|
addFormButton(formsContainer, "11. Egenmelding", 11);
|
||||||
for(int i = 0; i < mainLayout.getChildCount(); i++) {
|
addFormButton(formsContainer, "12. Sjekkliste for firmabil", 12);
|
||||||
View child = mainLayout.getChildAt(i);
|
addFormButton(formsContainer, "14. SJA (Sikker Jobbanalyse)", 14);
|
||||||
if (child instanceof TextView && ((TextView)child).getText().toString().contains("Tidligere")) {
|
addFormButton(formsContainer, "15. Fraværsvarsel", 15);
|
||||||
child.setVisibility(View.GONE);
|
addFormButton(formsContainer, "16. Refusjon utlegg", 16);
|
||||||
}
|
addFormButton(formsContainer, "21. Forberedelse til medarbeidersamtale", 21);
|
||||||
}
|
addFormButton(formsContainer, "22. Medarbeiderundersøkelse", 22);
|
||||||
}
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void addFormButton(LinearLayout container, String title, int formId) {
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
Button btn = new Button(getContext());
|
||||||
super.onViewCreated(view, savedInstanceState);
|
btn.setText(title);
|
||||||
fetchFormsList();
|
btn.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||||
}
|
btn.setTextColor(Color.WHITE);
|
||||||
|
btn.setPadding(30, 30, 30, 30);
|
||||||
private void fetchFormsList() {
|
|
||||||
if (container != null) container.removeAllViews();
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
|
||||||
if (txtStatus != null) txtStatus.setText("");
|
|
||||||
|
|
||||||
// Vi bruker standard-kallet som er raskt og effektivt
|
|
||||||
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
|
||||||
Map<String, GravityForm> formMap = response.body();
|
|
||||||
|
|
||||||
if (formMap.isEmpty()) {
|
|
||||||
if (txtStatus != null) txtStatus.setText("Ingen skjemaer funnet.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GravityForm> visibleForms = new ArrayList<>();
|
|
||||||
for (GravityForm form : formMap.values()) {
|
|
||||||
// Sjekk om aktiv
|
|
||||||
boolean isActive = form.isActive == null || !"0".equals(form.isActive);
|
|
||||||
|
|
||||||
// Sjekk om vi finner et sorteringstall i tittelen
|
|
||||||
Integer sortOrder = getSortOrderFromTitle(form.title);
|
|
||||||
|
|
||||||
if (form != null && form.title != null && isActive && sortOrder != null) {
|
|
||||||
visibleForms.add(form);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (visibleForms.isEmpty()) {
|
|
||||||
if (txtStatus != null) txtStatus.setText("Ingen tilgjengelige skjemaer (sjekk nummerering i titler).");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sorter listen basert på tallet i tittelen
|
|
||||||
Collections.sort(visibleForms, new Comparator<GravityForm>() {
|
|
||||||
@Override
|
|
||||||
public int compare(GravityForm f1, GravityForm f2) {
|
|
||||||
return Integer.compare(getSortOrderFromTitle(f1.title), getSortOrderFromTitle(f2.title));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for (GravityForm form : visibleForms) {
|
|
||||||
addFormButton(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (txtStatus != null) txtStatus.setText("Kunne ikke laste listen (Kode " + response.code() + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
|
||||||
if (txtStatus != null) txtStatus.setText("Nettverksfeil: " + t.getMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Henter ut tallet fra starten av tittelen.
|
|
||||||
* Returnerer null hvis tittelen ikke starter med et tall.
|
|
||||||
*/
|
|
||||||
private Integer getSortOrderFromTitle(String title) {
|
|
||||||
if (title == null) return null;
|
|
||||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
|
||||||
if (m.find()) {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(m.group(1));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null; // Ingen tall funnet -> Skjules
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Henter ut selve navnet på skjemaet (uten tallet foran).
|
|
||||||
* "10. Ansatte" -> "Ansatte"
|
|
||||||
*/
|
|
||||||
private String getCleanTitle(String title) {
|
|
||||||
if (title == null) return "";
|
|
||||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
|
||||||
if (m.find()) {
|
|
||||||
// Group 2 er resten av teksten etter tallet og punktum/mellomrom
|
|
||||||
return m.group(2);
|
|
||||||
}
|
|
||||||
return title; // Fallback hvis regex ikke matcher (skal ikke skje pga filtreringen over)
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addFormButton(GravityForm form) {
|
|
||||||
Button button = new Button(getContext());
|
|
||||||
|
|
||||||
// VIS VASKET TITTEL PÅ KNAPPEN
|
|
||||||
String displayTitle = getCleanTitle(form.title);
|
|
||||||
button.setText(displayTitle.toUpperCase());
|
|
||||||
|
|
||||||
button.setTextColor(Color.WHITE);
|
|
||||||
button.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
|
||||||
button.setTextSize(14);
|
|
||||||
button.setPadding(30, 30, 30, 30);
|
|
||||||
|
|
||||||
button.setOnClickListener(v -> {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putInt("formId", form.id);
|
|
||||||
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
|
||||||
});
|
|
||||||
|
|
||||||
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); // Litt avstand mellom knappene
|
||||||
params.setMargins(0, 0, 0, 20);
|
btn.setLayoutParams(params);
|
||||||
button.setLayoutParams(params);
|
|
||||||
|
|
||||||
container.addView(button);
|
btn.setOnClickListener(v -> {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putInt("formId", formId);
|
||||||
|
Navigation.findNavController(v).navigate(R.id.nav_forms, bundle);
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addView(btn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3212,79 +3314,130 @@ FILSTI: app\src\main\res\layout\activity_main.xml
|
||||||
FILSTI: app\src\main\res\layout\fragment_forms.xml
|
FILSTI: app\src\main\res\layout\fragment_forms.xml
|
||||||
============================================================
|
============================================================
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="16dp"
|
android:orientation="vertical"
|
||||||
android:background="@android:color/white">
|
android:background="#F5F5F5"
|
||||||
|
tools:context=".FormsFragment">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/main_layout"
|
android:id="@+id/history_wrapper"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:orientation="vertical">
|
android:layout_weight="3"
|
||||||
|
android:orientation="vertical"
|
||||||
<TextView
|
android:background="#FFFFFF"
|
||||||
android:layout_width="wrap_content"
|
android:elevation="4dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_marginBottom="8dp"
|
||||||
android:text="Skjema"
|
android:padding="16dp">
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:layout_marginBottom="16dp"/>
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/loading_spinner"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:visibility="visible" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/lbl_history"
|
android:id="@+id/lbl_history"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Tidligere innsendinger:"
|
android:text="Tidligere innsendinger"
|
||||||
android:textStyle="bold"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:layout_marginBottom="5dp"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/historyContainer"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginBottom="20dp"/>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="2dp"
|
|
||||||
android:background="#0069B3"
|
|
||||||
android:layout_marginBottom="20dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Ny innsending:"
|
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:textColor="#333333"
|
||||||
android:layout_marginBottom="10dp"/>
|
android:layout_marginBottom="10dp"/>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/historyContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="7"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="#FFFFFF"
|
||||||
|
android:elevation="4dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/form_container"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="#FAFAFA">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/loading_spinner"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_marginEnd="8dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/txt_status"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#666666"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/form_scroll_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/form_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="40dp">
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
FILSTI: app\src\main\res\layout\fragment_forms_list.xml
|
||||||
|
============================================================
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/main_layout" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="#F5F5F5">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/header_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Skjemaer"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:textColor="#333333"/>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/forms_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical" />
|
android:orientation="vertical" />
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
<TextView
|
</LinearLayout>
|
||||||
android:id="@+id/txt_status"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:textColor="#D32F2F"
|
|
||||||
android:gravity="center" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
============================================================
|
============================================================
|
||||||
FILSTI: app\src\main\res\layout\fragment_handbook.xml
|
FILSTI: app\src\main\res\layout\fragment_handbook.xml
|
||||||
|
|
@ -3836,6 +3989,14 @@ FILSTI: app\src\main\res\xml\data_extraction_rules.xml
|
||||||
-->
|
-->
|
||||||
</data-extraction-rules>
|
</data-extraction-rules>
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
FILSTI: app\src\main\res\xml\file_paths.xml
|
||||||
|
============================================================
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<external-files-path name="my_images" path="Pictures" />
|
||||||
|
</paths>
|
||||||
|
|
||||||
============================================================
|
============================================================
|
||||||
FILSTI: app\src\test\java\com\kbs\kbsintranett\ExampleUnitTest.java
|
FILSTI: app\src\test\java\com\kbs\kbsintranett\ExampleUnitTest.java
|
||||||
============================================================
|
============================================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue