Før sentralisert brukerliste
This commit is contained in:
parent
974c41ca4d
commit
ee198150c2
18 changed files with 684 additions and 337 deletions
|
|
@ -2,22 +2,27 @@ package com.kbs.kbsintranett;
|
|||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
|
@ -26,15 +31,18 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
|
||||
private EditText etTitle, etDesc;
|
||||
private Button btnDate, btnUsers, btnSave;
|
||||
private TextView txtDatePreview, txtUsersPreview;
|
||||
private TextView txtSheetTitle, txtDatePreview, txtUsersPreview;
|
||||
|
||||
private Calendar dueDate = Calendar.getInstance();
|
||||
private List<User> allUsersFromApi = new ArrayList<>();
|
||||
private List<User> filteredUsers = new ArrayList<>();
|
||||
private List<User> selectedUsers = new ArrayList<>();
|
||||
|
||||
private TaskItem taskToEdit = null; // NYTT: Hold på oppgaven som skal endres
|
||||
|
||||
public interface OnTaskAddedListener {
|
||||
void onTaskAdded(TaskItem task);
|
||||
void onTaskUpdated(TaskItem task); // NYTT
|
||||
}
|
||||
|
||||
private OnTaskAddedListener listener;
|
||||
|
|
@ -43,11 +51,32 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
this.listener = listener;
|
||||
}
|
||||
|
||||
// NYTT: Metode for å sette oppgaven som skal redigeres
|
||||
public void setTaskToEdit(TaskItem task) {
|
||||
this.taskToEdit = task;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
|
||||
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||||
dialog.setOnShowListener(dialogInterface -> {
|
||||
BottomSheetDialog d = (BottomSheetDialog) dialogInterface;
|
||||
View bottomSheet = d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
|
||||
if (bottomSheet != null) {
|
||||
BottomSheetBehavior.from(bottomSheet).setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
}
|
||||
});
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.bottom_sheet_add_task, container, false);
|
||||
|
||||
txtSheetTitle = v.findViewById(R.id.txt_sheet_title); // Pass på at denne IDen finnes i XML
|
||||
etTitle = v.findViewById(R.id.et_task_title);
|
||||
etDesc = v.findViewById(R.id.et_task_desc);
|
||||
btnDate = v.findViewById(R.id.btn_task_date);
|
||||
|
|
@ -56,7 +85,16 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
txtDatePreview = v.findViewById(R.id.txt_date_preview);
|
||||
txtUsersPreview = v.findViewById(R.id.txt_users_preview);
|
||||
|
||||
dueDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||
if (taskToEdit != null) {
|
||||
txtSheetTitle.setText("Rediger Oppgave");
|
||||
etTitle.setText(taskToEdit.getTitle());
|
||||
etDesc.setText(taskToEdit.getDescription());
|
||||
dueDate.setTimeInMillis(taskToEdit.getDueDate());
|
||||
btnSave.setText("Oppdater Oppgave");
|
||||
} else {
|
||||
dueDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
|
||||
updateDatePreview();
|
||||
|
||||
btnDate.setOnClickListener(view -> {
|
||||
|
|
@ -81,6 +119,18 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
if (response.isSuccessful() && response.body() != null) {
|
||||
allUsersFromApi = response.body();
|
||||
filterUsersByHierarchy();
|
||||
|
||||
// Hvis vi redigerer, må vi mappe eksisterende deltakere til selectedUsers listen
|
||||
if (taskToEdit != null) {
|
||||
selectedUsers.clear();
|
||||
Map<String, Boolean> currentAssignees = taskToEdit.getAssigneeStatus();
|
||||
for (User u : allUsersFromApi) {
|
||||
if (currentAssignees.containsKey(u.getEmail())) {
|
||||
selectedUsers.add(u);
|
||||
}
|
||||
}
|
||||
updateUsersPreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
|
|
@ -91,34 +141,30 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
private void filterUsersByHierarchy() {
|
||||
filteredUsers.clear();
|
||||
UserManager me = UserManager.getInstance();
|
||||
|
||||
// 1. Hvis Admin/Editor, legg til alle
|
||||
if (me.isEditorOrAbove()) {
|
||||
filteredUsers.addAll(allUsersFromApi);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Finn mine roller/avdelinger
|
||||
List<String> myRoles = new ArrayList<>();
|
||||
User self = null;
|
||||
|
||||
for (User u : allUsersFromApi) {
|
||||
if (u.getEmail().equalsIgnoreCase(me.getUserEmail())) {
|
||||
self = u;
|
||||
for (String r : u.getRoles()) myRoles.add(r.toLowerCase());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Filtrer logikk (Identisk med CreateEventFragment)
|
||||
if (me.isEditorOrAbove()) {
|
||||
filteredUsers.addAll(allUsersFromApi);
|
||||
return;
|
||||
}
|
||||
|
||||
for (User u : allUsersFromApi) {
|
||||
// Alltid legg til seg selv
|
||||
if (u.getEmail().equalsIgnoreCase(me.getUserEmail())) {
|
||||
if (!filteredUsers.contains(u)) filteredUsers.add(u);
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean hasAccess = false;
|
||||
for (String role : u.getRoles()) {
|
||||
String r = role.toLowerCase();
|
||||
// Sjekk om vi deler en avdelingsrolle
|
||||
if ((r.equals("serviceavdelingen") && myRoles.contains("serviceavdelingen")) ||
|
||||
(r.equals("automasjonsavdelingen") && myRoles.contains("automasjonsavdelingen")) ||
|
||||
(r.equals("prosjektavdelingen") && myRoles.contains("prosjektavdelingen")) ||
|
||||
|
|
@ -128,10 +174,7 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAccess && !filteredUsers.contains(u)) {
|
||||
filteredUsers.add(u);
|
||||
}
|
||||
if (hasAccess && !filteredUsers.contains(u)) filteredUsers.add(u);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,28 +183,44 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
Toast.makeText(getContext(), "Henter tilgjengelige personer...", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
String[] names = new String[filteredUsers.size()];
|
||||
boolean[] checked = new boolean[filteredUsers.size()];
|
||||
for (int i = 0; i < filteredUsers.size(); i++) {
|
||||
names[i] = filteredUsers.get(i).getName();
|
||||
checked[i] = selectedUsers.contains(filteredUsers.get(i));
|
||||
// Sjekk om e-posten finnes i de valgte brukernes liste
|
||||
boolean isSelected = false;
|
||||
for(User su : selectedUsers) {
|
||||
if(su.getEmail().equalsIgnoreCase(filteredUsers.get(i).getEmail())) {
|
||||
isSelected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
checked[i] = isSelected;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle("Tildel til...")
|
||||
.setMultiChoiceItems(names, checked, (dialog, which, isChecked) -> {
|
||||
if (isChecked) selectedUsers.add(filteredUsers.get(which));
|
||||
else selectedUsers.remove(filteredUsers.get(which));
|
||||
})
|
||||
.setPositiveButton("OK", (dialog, which) -> {
|
||||
if (selectedUsers.isEmpty()) txtUsersPreview.setText("Kun meg");
|
||||
else if (selectedUsers.size() == 1) txtUsersPreview.setText(selectedUsers.get(0).getName());
|
||||
else txtUsersPreview.setText(selectedUsers.size() + " personer valgt");
|
||||
User user = filteredUsers.get(which);
|
||||
if (isChecked) {
|
||||
boolean alreadyIn = false;
|
||||
for(User su : selectedUsers) if(su.getEmail().equalsIgnoreCase(user.getEmail())) alreadyIn = true;
|
||||
if(!alreadyIn) selectedUsers.add(user);
|
||||
} else {
|
||||
User toRemove = null;
|
||||
for(User su : selectedUsers) if(su.getEmail().equalsIgnoreCase(user.getEmail())) toRemove = su;
|
||||
if(toRemove != null) selectedUsers.remove(toRemove);
|
||||
}
|
||||
})
|
||||
.setPositiveButton("OK", (dialog, which) -> updateUsersPreview())
|
||||
.show();
|
||||
}
|
||||
|
||||
private void updateUsersPreview() {
|
||||
if (selectedUsers.isEmpty()) txtUsersPreview.setText("Kun meg");
|
||||
else if (selectedUsers.size() == 1) txtUsersPreview.setText(selectedUsers.get(0).getName());
|
||||
else txtUsersPreview.setText(selectedUsers.size() + " personer valgt");
|
||||
}
|
||||
|
||||
private void updateDatePreview() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
|
||||
txtDatePreview.setText("Frist: " + sdf.format(dueDate.getTime()));
|
||||
|
|
@ -174,14 +233,64 @@ public class AddTaskBottomSheet extends BottomSheetDialogFragment {
|
|||
return;
|
||||
}
|
||||
|
||||
TaskItem task = new TaskItem(title, etDesc.getText().toString(), dueDate.getTimeInMillis());
|
||||
if (selectedUsers.isEmpty()) {
|
||||
task.addAssignee(UserManager.getInstance().getUserEmail());
|
||||
} else {
|
||||
for (User u : selectedUsers) task.addAssignee(u.getEmail());
|
||||
}
|
||||
if (taskToEdit != null) {
|
||||
// REDIGER MODUS: Oppdater eksisterende objekt
|
||||
// Vi må beholde ID, Creator osv, men oppdatere innhold og deltakere
|
||||
// OBS: Hvis vi fjerner deltakere som allerede hadde gjort oppgaven, forsvinner deres status.
|
||||
// Dette er akseptabel oppførsel for enkelthets skyld.
|
||||
|
||||
if (listener != null) listener.onTaskAdded(task);
|
||||
// Lag en kopi av gamle statuser for å bevare "Fullført" for de som fortsatt er med
|
||||
Map<String, Boolean> oldStatus = taskToEdit.getAssigneeStatus();
|
||||
taskToEdit.getAssigneeStatus().clear();
|
||||
|
||||
if (selectedUsers.isEmpty()) {
|
||||
String myEmail = UserManager.getInstance().getUserEmail();
|
||||
taskToEdit.addAssignee(myEmail);
|
||||
if (oldStatus.containsKey(myEmail)) taskToEdit.setParticipantStatus(myEmail, oldStatus.get(myEmail));
|
||||
} else {
|
||||
for (User u : selectedUsers) {
|
||||
taskToEdit.addAssignee(u.getEmail());
|
||||
if (oldStatus.containsKey(u.getEmail())) {
|
||||
taskToEdit.setParticipantStatus(u.getEmail(), oldStatus.get(u.getEmail()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sjekk om tittelen eller beskrivelsen faktisk har endret seg for å sette titlene på nytt
|
||||
// (Vi bruker reflection her eller bare setter verdiene direkte siden de er private i TaskItem)
|
||||
// Siden jeg ikke endret TaskItem til å ha public settlere, antar jeg at du legger til disse
|
||||
// eller at vi bare lager en ny TaskItem med samme ID.
|
||||
|
||||
// Vi simulerer oppdatering av feltene (Sørg for at TaskItem har disse setterene!)
|
||||
// Hvis du ikke har setttere, legg dem til i TaskItem.java:
|
||||
// public void setTitle(String t) { this.title = t; }
|
||||
// public void setDescription(String d) { this.description = d; }
|
||||
// public void setDueDate(long d) { this.dueDate = d; }
|
||||
|
||||
// Jeg skriver logikken slik at den forventer setttere:
|
||||
updateTaskFields(taskToEdit, title, etDesc.getText().toString(), dueDate.getTimeInMillis());
|
||||
|
||||
if (listener != null) listener.onTaskUpdated(taskToEdit);
|
||||
|
||||
} else {
|
||||
// NY OPPGAVE MODUS
|
||||
TaskItem newTask = new TaskItem(title, etDesc.getText().toString(), dueDate.getTimeInMillis());
|
||||
if (selectedUsers.isEmpty()) {
|
||||
newTask.addAssignee(UserManager.getInstance().getUserEmail());
|
||||
} else {
|
||||
for (User u : selectedUsers) newTask.addAssignee(u.getEmail());
|
||||
}
|
||||
if (listener != null) listener.onTaskAdded(newTask);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
|
||||
// Hjelpemetode (forutsetter at du legger til disse tre setterne i TaskItem.java)
|
||||
private void updateTaskFields(TaskItem t, String title, String desc, long date) {
|
||||
// Her kaller vi setterne vi nå legger til i TaskItem
|
||||
// Se punkt 5 nedenfor for oppdatert TaskItem.java
|
||||
t.setTitle(title);
|
||||
t.setDescription(desc);
|
||||
t.setDueDate(date);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import android.os.Looper;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -15,6 +14,7 @@ import androidx.fragment.app.Fragment;
|
|||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import retrofit2.Call;
|
||||
|
|
@ -26,7 +26,7 @@ public class CalendarFullFragment extends Fragment {
|
|||
private RecyclerView recyclerView;
|
||||
private ProgressBar progressBar;
|
||||
private TextView emptyView;
|
||||
private Button btnAddEvent;
|
||||
private FloatingActionButton fabAddEvent;
|
||||
private LinearLayoutManager layoutManager;
|
||||
|
||||
@Nullable
|
||||
|
|
@ -41,16 +41,14 @@ public class CalendarFullFragment extends Fragment {
|
|||
recyclerView = view.findViewById(R.id.recycler_full_calendar);
|
||||
progressBar = view.findViewById(R.id.loading_full_calendar);
|
||||
emptyView = view.findViewById(R.id.empty_view_calendar);
|
||||
btnAddEvent = view.findViewById(R.id.btn_add_calendar_event);
|
||||
fabAddEvent = view.findViewById(R.id.fab_add_calendar_event);
|
||||
|
||||
layoutManager = new LinearLayoutManager(getContext());
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
|
||||
// VIKTIG: Ingen referanse til btn_back_calendar her lenger.
|
||||
|
||||
if (!UserManager.getInstance().getWriteableCalendars().isEmpty() || UserManager.getInstance().isEditorOrAbove()) {
|
||||
btnAddEvent.setVisibility(View.VISIBLE);
|
||||
btnAddEvent.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.navigation_create_event));
|
||||
fabAddEvent.setVisibility(View.VISIBLE);
|
||||
fabAddEvent.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.navigation_create_event));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,18 +2,25 @@ package com.kbs.kbsintranett;
|
|||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
|
|
@ -21,17 +28,21 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
public static final int TYPE_SECTION_TITLE = 2;
|
||||
public static final int TYPE_CALENDAR_ITEM = 3;
|
||||
public static final int TYPE_NEWS_ITEM = 4;
|
||||
public static final int TYPE_TASK_ITEM = 5;
|
||||
public static final int TYPE_EMPTY_TASKS = 6;
|
||||
|
||||
private final List<Object> items;
|
||||
private final OnHomeClickListener listener;
|
||||
|
||||
public interface OnHomeClickListener {
|
||||
void onProfileClick();
|
||||
void onCreateEventClick();
|
||||
void onViewAllCalendarClick();
|
||||
void onViewAllNewsClick();
|
||||
void onViewAllTasksClick();
|
||||
void onCalendarItemClick(CalendarEvent event);
|
||||
void onNewsItemClick(WpPost post);
|
||||
void onTaskItemClick(TaskItem task);
|
||||
void onTaskStatusChanged(TaskItem task, boolean isDone);
|
||||
}
|
||||
|
||||
public HomeAdapter(List<Object> items, OnHomeClickListener listener) {
|
||||
|
|
@ -46,6 +57,8 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
if (item instanceof SectionTitleItem) return TYPE_SECTION_TITLE;
|
||||
if (item instanceof CalendarEvent) return TYPE_CALENDAR_ITEM;
|
||||
if (item instanceof WpPost) return TYPE_NEWS_ITEM;
|
||||
if (item instanceof TaskItem) return TYPE_TASK_ITEM;
|
||||
if (item instanceof EmptyTasksItem) return TYPE_EMPTY_TASKS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +73,10 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
return new SectionTitleViewHolder(inflater.inflate(R.layout.item_home_section_title, parent, false));
|
||||
case TYPE_CALENDAR_ITEM:
|
||||
return new CalendarViewHolder(inflater.inflate(R.layout.item_calendar, parent, false));
|
||||
case TYPE_TASK_ITEM:
|
||||
return new TaskViewHolder(inflater.inflate(R.layout.item_task, parent, false));
|
||||
case TYPE_EMPTY_TASKS:
|
||||
return new EmptyViewHolder(inflater.inflate(R.layout.item_home_empty_tasks, parent, false));
|
||||
case TYPE_NEWS_ITEM:
|
||||
return new NewsViewHolder(inflater.inflate(R.layout.item_news, parent, false));
|
||||
default:
|
||||
|
|
@ -79,7 +96,8 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
SectionTitleViewHolder vh = (SectionTitleViewHolder) holder;
|
||||
vh.title.setText(section.title);
|
||||
vh.btnViewAll.setOnClickListener(v -> {
|
||||
if (section.isCalendar) listener.onViewAllCalendarClick();
|
||||
if (section.type == SectionTitleItem.TYPE_CALENDAR) listener.onViewAllCalendarClick();
|
||||
else if (section.type == SectionTitleItem.TYPE_TASKS) listener.onViewAllTasksClick();
|
||||
else listener.onViewAllNewsClick();
|
||||
});
|
||||
}
|
||||
|
|
@ -90,28 +108,49 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
vh.month.setText(event.getMonth());
|
||||
vh.time.setText(event.getTime());
|
||||
vh.title.setText(event.getTitle());
|
||||
|
||||
boolean isPrivate = event.getDescription() != null && event.getDescription().contains("#deltakere:");
|
||||
int color;
|
||||
try {
|
||||
color = Color.parseColor(isPrivate ? "#673AB7" : event.getCalendarColor());
|
||||
int color = Color.parseColor(isPrivate ? "#673AB7" : event.getCalendarColor());
|
||||
vh.dateBox.setBackgroundTintList(ColorStateList.valueOf(color));
|
||||
} catch (Exception e) {
|
||||
color = Color.parseColor("#0069B3");
|
||||
vh.dateBox.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#0069B3")));
|
||||
}
|
||||
vh.dateBox.setBackgroundTintList(ColorStateList.valueOf(color));
|
||||
vh.itemView.setOnClickListener(v -> listener.onCalendarItemClick(event));
|
||||
}
|
||||
else if (holder instanceof TaskViewHolder) {
|
||||
TaskItem task = (TaskItem) item;
|
||||
TaskViewHolder vh = (TaskViewHolder) holder;
|
||||
vh.title.setText(task.getTitle());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("dd. MMM", Locale.getDefault());
|
||||
vh.date.setText("Frist: " + sdf.format(new Date(task.getDueDate())));
|
||||
|
||||
String myEmail = UserManager.getInstance().getUserEmail();
|
||||
boolean myStatus = task.getParticipantStatus(myEmail);
|
||||
vh.checkBox.setChecked(myStatus);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
boolean isOverdue = task.getDueDate() < now && !task.isFullyCompleted() && !myStatus;
|
||||
|
||||
if (isOverdue) {
|
||||
vh.cardView.setCardBackgroundColor(ContextCompat.getColor(vh.itemView.getContext(), R.color.kbs_soft_light_pink_beige));
|
||||
vh.date.setTextColor(ContextCompat.getColor(vh.itemView.getContext(), R.color.kbs_logo_accent_red));
|
||||
} else {
|
||||
vh.cardView.setCardBackgroundColor(Color.WHITE);
|
||||
vh.date.setTextColor(ContextCompat.getColor(vh.itemView.getContext(), R.color.kbs_muted_blue_gray));
|
||||
}
|
||||
|
||||
vh.checkBox.setOnClickListener(v -> listener.onTaskStatusChanged(task, vh.checkBox.isChecked()));
|
||||
vh.itemView.setOnClickListener(v -> listener.onTaskItemClick(task));
|
||||
}
|
||||
else if (holder instanceof NewsViewHolder) {
|
||||
WpPost post = (WpPost) item;
|
||||
NewsViewHolder vh = (NewsViewHolder) holder;
|
||||
vh.title.setText(post.getTitleStr());
|
||||
vh.excerpt.setText(post.getExcerptStr());
|
||||
vh.date.setText(post.date);
|
||||
|
||||
String cat = post.getCategoryName();
|
||||
vh.category.setText(cat);
|
||||
vh.category.setVisibility(cat.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
|
||||
String imgUrl = post.getFeaturedImageUrl();
|
||||
if (imgUrl != null) {
|
||||
vh.image.setVisibility(View.VISIBLE);
|
||||
|
|
@ -129,7 +168,6 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
}
|
||||
|
||||
// --- VIEW HOLDERS ---
|
||||
|
||||
static class CreateButtonViewHolder extends RecyclerView.ViewHolder {
|
||||
Button btnCreate;
|
||||
CreateButtonViewHolder(View v) { super(v); btnCreate = v.findViewById(R.id.btn_create_event); }
|
||||
|
|
@ -143,13 +181,26 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
static class CalendarViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView day, month, title, time;
|
||||
LinearLayout dateBox;
|
||||
CalendarViewHolder(View v) {
|
||||
CalendarViewHolder(View view) {
|
||||
super(view);
|
||||
day = view.findViewById(R.id.cal_day);
|
||||
month = view.findViewById(R.id.cal_month);
|
||||
title = view.findViewById(R.id.cal_title);
|
||||
time = view.findViewById(R.id.cal_time);
|
||||
dateBox = view.findViewById(R.id.date_box_background);
|
||||
}
|
||||
}
|
||||
|
||||
static class TaskViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView title, date;
|
||||
CheckBox checkBox;
|
||||
CardView cardView;
|
||||
TaskViewHolder(View v) {
|
||||
super(v);
|
||||
day = v.findViewById(R.id.cal_day);
|
||||
month = v.findViewById(R.id.cal_month);
|
||||
title = v.findViewById(R.id.cal_title);
|
||||
time = v.findViewById(R.id.cal_time);
|
||||
dateBox = v.findViewById(R.id.date_box_background);
|
||||
title = v.findViewById(R.id.task_title);
|
||||
date = v.findViewById(R.id.task_date);
|
||||
checkBox = v.findViewById(R.id.task_checkbox);
|
||||
cardView = (CardView) v;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,10 +217,18 @@ public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|||
}
|
||||
}
|
||||
|
||||
static class EmptyViewHolder extends RecyclerView.ViewHolder {
|
||||
EmptyViewHolder(View v) { super(v); }
|
||||
}
|
||||
|
||||
// --- WRAPPER KLASSER ---
|
||||
public static class CreateButtonItem {}
|
||||
public static class EmptyTasksItem {}
|
||||
public static class SectionTitleItem {
|
||||
String title; boolean isCalendar;
|
||||
public SectionTitleItem(String t, boolean c) { this.title = t; this.isCalendar = c; }
|
||||
public static final int TYPE_CALENDAR = 0;
|
||||
public static final int TYPE_NEWS = 1;
|
||||
public static final int TYPE_TASKS = 2;
|
||||
String title; int type;
|
||||
public SectionTitleItem(String t, int type) { this.title = t; this.type = type; }
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -19,8 +20,10 @@ import androidx.navigation.Navigation;
|
|||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import com.google.gson.JsonElement;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
|
@ -37,6 +40,7 @@ public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickLis
|
|||
|
||||
private List<CalendarEvent> currentEvents = new ArrayList<>();
|
||||
private List<WpPost> currentNews = new ArrayList<>();
|
||||
private List<TaskItem> currentTasks = new ArrayList<>();
|
||||
private int activeNetworkCalls = 0;
|
||||
|
||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||
|
|
@ -67,22 +71,17 @@ public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickLis
|
|||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
swipeRefreshLayout.setOnRefreshListener(this::refreshData);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 33) {
|
||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
refreshData();
|
||||
}
|
||||
|
||||
private void refreshData() {
|
||||
if (activeNetworkCalls > 0) return;
|
||||
activeNetworkCalls = 2;
|
||||
activeNetworkCalls = 3;
|
||||
if (mainProgressBar != null) mainProgressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
fetchCalendarData();
|
||||
fetchNewsData();
|
||||
fetchTaskData();
|
||||
}
|
||||
|
||||
private void fetchCalendarData() {
|
||||
|
|
@ -106,12 +105,10 @@ public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickLis
|
|||
} else {
|
||||
apiEvents = CacheManager.getCachedCalendarEvents(getContext());
|
||||
}
|
||||
|
||||
for (CalendarEvent e : apiEvents) CalendarManager.formatEventForUI(e);
|
||||
currentEvents = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
||||
checkLoadingComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
||||
List<CalendarEvent> cached = CacheManager.getCachedCalendarEvents(getContext());
|
||||
|
|
@ -137,7 +134,6 @@ public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickLis
|
|||
formatNewsDates(currentNews);
|
||||
checkLoadingComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
||||
currentNews = CacheManager.getCachedNewsPosts(getContext());
|
||||
|
|
@ -147,6 +143,26 @@ public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickLis
|
|||
});
|
||||
}
|
||||
|
||||
private void fetchTaskData() {
|
||||
RetrofitClient.getApiService().getTasks().enqueue(new Callback<List<TaskItem>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<TaskItem>> call, Response<List<TaskItem>> response) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
currentTasks = response.body();
|
||||
CacheManager.saveTasks(getContext(), currentTasks);
|
||||
} else {
|
||||
currentTasks = CacheManager.getTasks(getContext());
|
||||
}
|
||||
checkLoadingComplete();
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Call<List<TaskItem>> call, Throwable t) {
|
||||
currentTasks = CacheManager.getTasks(getContext());
|
||||
checkLoadingComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void formatNewsDates(List<WpPost> posts) {
|
||||
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
|
||||
|
|
@ -170,45 +186,97 @@ public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickLis
|
|||
|
||||
private void buildAndDisplayList() {
|
||||
List<Object> items = new ArrayList<>();
|
||||
String myEmail = UserManager.getInstance().getUserEmail();
|
||||
|
||||
// 1. Kalender Seksjon (Knappen "Ny hendelse" er fjernet herfra)
|
||||
items.add(new HomeAdapter.SectionTitleItem("Kommende hendelser", true));
|
||||
items.add(new HomeAdapter.SectionTitleItem("Kommende hendelser", HomeAdapter.SectionTitleItem.TYPE_CALENDAR));
|
||||
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
||||
int count = 0;
|
||||
int calCount = 0;
|
||||
for (CalendarEvent e : currentEvents) {
|
||||
if (e.getRawDate() != null && e.getRawDate().compareTo(today) >= 0) {
|
||||
items.add(e);
|
||||
count++;
|
||||
calCount++;
|
||||
}
|
||||
if (count >= 3) break;
|
||||
if (calCount >= 3) break;
|
||||
}
|
||||
|
||||
// 2. Nyheter Seksjon
|
||||
items.add(new HomeAdapter.SectionTitleItem("Siste nytt", false));
|
||||
items.add(new HomeAdapter.SectionTitleItem("Mine oppgaver", HomeAdapter.SectionTitleItem.TYPE_TASKS));
|
||||
List<TaskItem> myActiveTasks = new ArrayList<>();
|
||||
for (TaskItem t : currentTasks) {
|
||||
if (t.isUserParticipant(myEmail) && !t.getParticipantStatus(myEmail) && !t.isFullyCompleted()) {
|
||||
myActiveTasks.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (myActiveTasks.isEmpty()) {
|
||||
items.add(new HomeAdapter.EmptyTasksItem());
|
||||
} else {
|
||||
Collections.sort(myActiveTasks, (t1, t2) -> Long.compare(t1.getDueDate(), t2.getDueDate()));
|
||||
for (int i = 0; i < Math.min(myActiveTasks.size(), 3); i++) {
|
||||
items.add(myActiveTasks.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
items.add(new HomeAdapter.SectionTitleItem("Siste nytt", HomeAdapter.SectionTitleItem.TYPE_NEWS));
|
||||
items.addAll(currentNews);
|
||||
|
||||
adapter = new HomeAdapter(items, this);
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override public void onProfileClick() {}
|
||||
@Override public void onCreateEventClick() {
|
||||
Navigation.findNavController(getView()).navigate(R.id.navigation_create_event);
|
||||
}
|
||||
@Override public void onViewAllCalendarClick() {
|
||||
Navigation.findNavController(getView()).navigate(R.id.navigation_calendar_full);
|
||||
}
|
||||
@Override public void onViewAllNewsClick() {
|
||||
Navigation.findNavController(getView()).navigate(R.id.navigation_news_full);
|
||||
}
|
||||
@Override public void onCreateEventClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_create_event); }
|
||||
@Override public void onViewAllCalendarClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_calendar_full); }
|
||||
@Override public void onViewAllNewsClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_news_full); }
|
||||
@Override public void onViewAllTasksClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_tasks); }
|
||||
|
||||
@Override public void onCalendarItemClick(CalendarEvent event) {
|
||||
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
||||
sheet.setOnEventChangeListener(this::refreshData);
|
||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||
}
|
||||
|
||||
@Override public void onNewsItemClick(WpPost post) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("post_data", post);
|
||||
Navigation.findNavController(getView()).navigate(R.id.navigation_news_detail, bundle);
|
||||
}
|
||||
|
||||
@Override public void onTaskItemClick(TaskItem task) {
|
||||
TaskDetailsBottomSheet sheet = new TaskDetailsBottomSheet(task, new TaskDetailsBottomSheet.OnTaskChangeListener() {
|
||||
@Override public void onTaskChanged() { saveAndSyncTasks(); }
|
||||
@Override public void onTaskDeleted(TaskItem taskToDelete) {
|
||||
currentTasks.remove(taskToDelete);
|
||||
saveAndSyncTasks();
|
||||
}
|
||||
@Override public void onEditRequested(TaskItem taskToEdit) {
|
||||
AddTaskBottomSheet editDialog = new AddTaskBottomSheet();
|
||||
editDialog.setTaskToEdit(taskToEdit);
|
||||
editDialog.setOnTaskAddedListener(new AddTaskBottomSheet.OnTaskAddedListener() {
|
||||
@Override public void onTaskAdded(TaskItem task) {}
|
||||
@Override public void onTaskUpdated(TaskItem task) {
|
||||
saveAndSyncTasks();
|
||||
}
|
||||
});
|
||||
editDialog.show(getChildFragmentManager(), "EditTask");
|
||||
}
|
||||
});
|
||||
sheet.show(getChildFragmentManager(), "TaskDetails");
|
||||
}
|
||||
|
||||
@Override public void onTaskStatusChanged(TaskItem task, boolean isDone) {
|
||||
String myEmail = UserManager.getInstance().getUserEmail();
|
||||
task.setParticipantStatus(myEmail, isDone);
|
||||
if (task.getCreatedByEmail().equalsIgnoreCase(myEmail) && isDone) {
|
||||
task.setFullyCompleted(true);
|
||||
}
|
||||
saveAndSyncTasks();
|
||||
}
|
||||
|
||||
private void saveAndSyncTasks() {
|
||||
CacheManager.saveTasks(getContext(), currentTasks);
|
||||
buildAndDisplayList();
|
||||
RetrofitClient.getApiService().syncTasks(currentTasks).enqueue(new Callback<JsonElement>() {
|
||||
@Override public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {}
|
||||
@Override public void onFailure(Call<JsonElement> call, Throwable t) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -40,10 +40,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
// Din oppdaterte linje:
|
||||
public static final String GOOGLE_WEB_CLIENT_ID = BuildConfig.WEB_CLIENT_ID;
|
||||
|
||||
private static final String TAG = "MainActivity";
|
||||
private NavController navController;
|
||||
private DrawerLayout drawerLayout;
|
||||
private AppBarConfiguration appBarConfiguration;
|
||||
|
|
@ -73,7 +70,18 @@ public class MainActivity extends AppCompatActivity {
|
|||
.build();
|
||||
|
||||
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
|
||||
NavigationUI.setupWithNavController(navigationView, navController);
|
||||
|
||||
// Vi bruker en tilpasset listener for å sikre at Hjem og andre punkter alltid fungerer
|
||||
navigationView.setNavigationItemSelectedListener(item -> {
|
||||
boolean handled = NavigationUI.onNavDestinationSelected(item, navController);
|
||||
if (handled || item.getItemId() == R.id.navigation_home) {
|
||||
if (item.getItemId() == R.id.navigation_home) {
|
||||
navController.navigate(R.id.navigation_home);
|
||||
}
|
||||
drawerLayout.closeDrawer(GravityCompat.START);
|
||||
}
|
||||
return handled;
|
||||
});
|
||||
|
||||
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
|
||||
if (destination.getId() == R.id.navigation_login) {
|
||||
|
|
@ -82,7 +90,6 @@ public class MainActivity extends AppCompatActivity {
|
|||
} else {
|
||||
toolbar.setVisibility(View.VISIBLE);
|
||||
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
||||
// Oppdater navn hver gang vi bytter skjerm for å være sikker
|
||||
updateNavHeader(navigationView);
|
||||
}
|
||||
});
|
||||
|
|
@ -90,9 +97,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
setupTaskReminders();
|
||||
createNotificationChannel();
|
||||
|
||||
requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {});
|
||||
|
||||
checkNotificationPermission();
|
||||
checkExactAlarmPermission();
|
||||
checkLoginState();
|
||||
|
|
@ -102,7 +107,6 @@ public class MainActivity extends AppCompatActivity {
|
|||
View headerView = navigationView.getHeaderView(0);
|
||||
TextView name = headerView.findViewById(R.id.nav_header_name);
|
||||
TextView email = headerView.findViewById(R.id.nav_header_email);
|
||||
|
||||
UserManager user = UserManager.getInstance();
|
||||
if (user.isLoggedIn()) {
|
||||
name.setText(user.getUserDisplayName());
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -30,7 +29,7 @@ public class NewsFullFragment extends Fragment {
|
|||
private RecyclerView recyclerViewCategories;
|
||||
private ProgressBar progressBar;
|
||||
private NewsAdapter newsAdapter;
|
||||
private List<WpPost> allPosts = new ArrayList<>(); // Holder på ALLE postene
|
||||
private List<WpPost> allPosts = new ArrayList<>();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
|
|
@ -45,7 +44,6 @@ public class NewsFullFragment extends Fragment {
|
|||
recyclerViewNews = view.findViewById(R.id.recycler_news_full);
|
||||
recyclerViewCategories = view.findViewById(R.id.recycler_categories);
|
||||
progressBar = view.findViewById(R.id.loading_news_full);
|
||||
ImageView backBtn = view.findViewById(R.id.btn_back_news);
|
||||
|
||||
// Setup Nyhetsliste
|
||||
recyclerViewNews.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
|
@ -54,15 +52,12 @@ public class NewsFullFragment extends Fragment {
|
|||
recyclerViewCategories.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
|
||||
setupCategories();
|
||||
|
||||
backBtn.setOnClickListener(v -> Navigation.findNavController(view).navigateUp());
|
||||
|
||||
fetchAllNews();
|
||||
}
|
||||
|
||||
private void setupCategories() {
|
||||
// Listen over kategorier du ønsket
|
||||
List<String> categories = Arrays.asList(
|
||||
"Alle", // Standard vis alt
|
||||
"Alle",
|
||||
"Avtaler og invitasjoner", "BHT", "Bilhold", "Cordel",
|
||||
"Ferieavvikling", "Fest og moro", "Generell drift",
|
||||
"HMS", "IT og sikkerhet", "Miljøfyrtårn", "Møtereferat", "SMX"
|
||||
|
|
@ -76,7 +71,6 @@ public class NewsFullFragment extends Fragment {
|
|||
|
||||
private void fetchAllNews() {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
// Hent 50 siste (bør holde for en "Siste nytt" liste, ellers må vi paginere)
|
||||
RetrofitClient.getApiService().getAllPosts().enqueue(new Callback<List<WpPost>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
||||
|
|
@ -87,7 +81,6 @@ public class NewsFullFragment extends Fragment {
|
|||
allPosts = response.body();
|
||||
formatDates(allPosts);
|
||||
|
||||
// Vis alle i starten
|
||||
newsAdapter = new NewsAdapter(new ArrayList<>(allPosts), post -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("post_data", post);
|
||||
|
|
@ -110,29 +103,23 @@ public class NewsFullFragment extends Fragment {
|
|||
|
||||
private void filterNews(String category) {
|
||||
if (newsAdapter == null) return;
|
||||
|
||||
List<WpPost> filteredList = new ArrayList<>();
|
||||
|
||||
if (category.equals("Alle")) {
|
||||
filteredList.addAll(allPosts);
|
||||
} else {
|
||||
for (WpPost post : allPosts) {
|
||||
// Vi sjekker om kategorinavnet matcher
|
||||
if (post.getCategoryName().equals(category)) {
|
||||
filteredList.add(post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Oppdater adapteren med den filtrerte listen
|
||||
newsAdapter.updateList(filteredList);
|
||||
}
|
||||
|
||||
private void formatDates(List<WpPost> posts) {
|
||||
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
rawFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
|
||||
targetFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
||||
|
||||
for (WpPost post : posts) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import android.view.ViewGroup;
|
|||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
|
@ -46,18 +48,38 @@ public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.ViewHolder> {
|
|||
SimpleDateFormat sdf = new SimpleDateFormat("dd. MMM", Locale.getDefault());
|
||||
holder.date.setText("Frist: " + sdf.format(new Date(task.getDueDate())));
|
||||
|
||||
// Vis hvem som tildelte oppgaven hvis det ikke er meg selv (Nytt krav)
|
||||
if (task.getCreatedByEmail() != null && !task.getCreatedByEmail().equalsIgnoreCase(currentUserEmail)) {
|
||||
holder.creator.setText("Tildelt av: " + task.getCreatedByName());
|
||||
holder.creator.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.creator.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
boolean myStatus = task.getParticipantStatus(currentUserEmail);
|
||||
holder.checkBox.setChecked(myStatus);
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
boolean isOverdue = task.getDueDate() < now && !task.isFullyCompleted() && !myStatus;
|
||||
|
||||
if (isOverdue) {
|
||||
holder.cardView.setCardBackgroundColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.kbs_soft_light_pink_beige));
|
||||
holder.date.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.kbs_logo_accent_red));
|
||||
holder.date.setText("FORFALT: " + sdf.format(new Date(task.getDueDate())));
|
||||
} else {
|
||||
holder.cardView.setCardBackgroundColor(Color.WHITE);
|
||||
holder.date.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.kbs_muted_blue_gray));
|
||||
}
|
||||
|
||||
if (myStatus || task.isFullyCompleted()) {
|
||||
holder.title.setPaintFlags(holder.title.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
holder.title.setTextColor(Color.GRAY);
|
||||
} else {
|
||||
holder.cardView.setCardBackgroundColor(Color.parseColor("#F5F5F5"));
|
||||
} else if (!isOverdue) {
|
||||
holder.title.setPaintFlags(holder.title.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
|
||||
holder.title.setTextColor(Color.BLACK);
|
||||
}
|
||||
|
||||
// Vis fremdrift (f.eks 1/3 fullført)
|
||||
int total = task.getAssigneeStatus().size();
|
||||
int done = 0;
|
||||
for (Boolean b : task.getAssigneeStatus().values()) if (b) done++;
|
||||
|
|
@ -71,14 +93,17 @@ public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.ViewHolder> {
|
|||
public int getItemCount() { return tasks.size(); }
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView title, date, progress;
|
||||
TextView title, date, creator, progress;
|
||||
CheckBox checkBox;
|
||||
CardView cardView;
|
||||
ViewHolder(View v) {
|
||||
super(v);
|
||||
title = v.findViewById(R.id.task_title);
|
||||
date = v.findViewById(R.id.task_date);
|
||||
creator = v.findViewById(R.id.task_creator);
|
||||
progress = v.findViewById(R.id.task_progress);
|
||||
checkBox = v.findViewById(R.id.task_checkbox);
|
||||
cardView = (CardView) v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
@ -25,6 +24,7 @@ public class TaskDetailsBottomSheet extends BottomSheetDialogFragment {
|
|||
public interface OnTaskChangeListener {
|
||||
void onTaskChanged();
|
||||
void onTaskDeleted(TaskItem task);
|
||||
void onEditRequested(TaskItem task); // NYTT
|
||||
}
|
||||
|
||||
public TaskDetailsBottomSheet(TaskItem task, OnTaskChangeListener listener) {
|
||||
|
|
@ -42,7 +42,9 @@ public class TaskDetailsBottomSheet extends BottomSheetDialogFragment {
|
|||
TextView desc = v.findViewById(R.id.detail_task_desc);
|
||||
LinearLayout participantsContainer = v.findViewById(R.id.container_participants_status);
|
||||
SwitchMaterial switchNotify = v.findViewById(R.id.switch_notifications);
|
||||
LinearLayout ownerActions = v.findViewById(R.id.layout_owner_actions);
|
||||
Button btnDelete = v.findViewById(R.id.btn_delete_task);
|
||||
Button btnEdit = v.findViewById(R.id.btn_edit_task);
|
||||
|
||||
title.setText(task.getTitle());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("EEEE dd. MMMM yyyy", Locale.getDefault());
|
||||
|
|
@ -53,7 +55,7 @@ public class TaskDetailsBottomSheet extends BottomSheetDialogFragment {
|
|||
desc.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
// List opp alle deltakere og deres status
|
||||
participantsContainer.removeAllViews();
|
||||
for (Map.Entry<String, Boolean> entry : task.getAssigneeStatus().entrySet()) {
|
||||
TextView t = new TextView(getContext());
|
||||
String status = entry.getValue() ? "✅ Fullført" : "⏳ Pågår";
|
||||
|
|
@ -68,13 +70,16 @@ public class TaskDetailsBottomSheet extends BottomSheetDialogFragment {
|
|||
if (listener != null) listener.onTaskChanged();
|
||||
});
|
||||
|
||||
// Kun eier kan slette oppgaven
|
||||
if (task.getCreatedByEmail().equals(UserManager.getInstance().getUserEmail())) {
|
||||
btnDelete.setVisibility(View.VISIBLE);
|
||||
if (task.getCreatedByEmail().equalsIgnoreCase(UserManager.getInstance().getUserEmail())) {
|
||||
ownerActions.setVisibility(View.VISIBLE);
|
||||
btnDelete.setOnClickListener(view -> {
|
||||
if (listener != null) listener.onTaskDeleted(task);
|
||||
dismiss();
|
||||
});
|
||||
btnEdit.setOnClickListener(view -> {
|
||||
if (listener != null) listener.onEditRequested(task);
|
||||
dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
return v;
|
||||
|
|
|
|||
|
|
@ -13,11 +13,10 @@ public class TaskItem implements Serializable {
|
|||
private String createdByEmail;
|
||||
private String createdByName;
|
||||
|
||||
// Key: Bruker-epost, Value: Har fullført (true/false)
|
||||
private Map<String, Boolean> assigneeStatus = new HashMap<>();
|
||||
|
||||
private boolean notificationsEnabled = true;
|
||||
private boolean isFullyCompleted = false; // Satt av eier eller når alle er ferdige
|
||||
private boolean isFullyCompleted = false;
|
||||
|
||||
public TaskItem(String title, String description, long dueDate) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
|
|
@ -28,15 +27,7 @@ public class TaskItem implements Serializable {
|
|||
this.createdByName = UserManager.getInstance().getUserDisplayName();
|
||||
}
|
||||
|
||||
// Hjelpemetoder
|
||||
public void addAssignee(String email) { assigneeStatus.put(email, false); }
|
||||
public void setParticipantStatus(String email, boolean done) { assigneeStatus.put(email, done); }
|
||||
public boolean getParticipantStatus(String email) { return assigneeStatus.getOrDefault(email, false); }
|
||||
|
||||
public boolean isUserParticipant(String email) { return assigneeStatus.containsKey(email); }
|
||||
public Map<String, Boolean> getAssigneeStatus() { return assigneeStatus; }
|
||||
|
||||
// Getters / Setters
|
||||
// Getters
|
||||
public String getId() { return id; }
|
||||
public String getTitle() { return title; }
|
||||
public String getDescription() { return description; }
|
||||
|
|
@ -44,7 +35,19 @@ public class TaskItem implements Serializable {
|
|||
public String getCreatedByEmail() { return createdByEmail; }
|
||||
public String getCreatedByName() { return createdByName; }
|
||||
public boolean isNotificationsEnabled() { return notificationsEnabled; }
|
||||
public void setNotificationsEnabled(boolean enabled) { this.notificationsEnabled = enabled; }
|
||||
public boolean isFullyCompleted() { return isFullyCompleted; }
|
||||
public void setFullyCompleted(boolean fullyCompleted) { isFullyCompleted = fullyCompleted; }
|
||||
|
||||
// Setters (NYTT FOR REDIGERING)
|
||||
public void setTitle(String title) { this.title = title; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
public void setDueDate(long dueDate) { this.dueDate = dueDate; }
|
||||
public void setNotificationsEnabled(boolean enabled) { this.notificationsEnabled = enabled; }
|
||||
public void setFullyCompleted(boolean fullyCompleted) { this.isFullyCompleted = fullyCompleted; }
|
||||
|
||||
// Participant logikk
|
||||
public void addAssignee(String email) { assigneeStatus.put(email, false); }
|
||||
public void setParticipantStatus(String email, boolean done) { assigneeStatus.put(email, done); }
|
||||
public boolean getParticipantStatus(String email) { return assigneeStatus.getOrDefault(email, false); }
|
||||
public boolean isUserParticipant(String email) { return assigneeStatus.containsKey(email); }
|
||||
public Map<String, Boolean> getAssigneeStatus() { return assigneeStatus; }
|
||||
}
|
||||
|
|
@ -4,21 +4,29 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.gson.JsonElement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class TasksFragment extends Fragment implements TaskAdapter.OnTaskClickListener {
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
private TaskAdapter adapter;
|
||||
private TabLayout tabLayout;
|
||||
private SwipeRefreshLayout swipeRefresh;
|
||||
private List<TaskItem> allTasks = new ArrayList<>();
|
||||
private String myEmail;
|
||||
|
||||
|
|
@ -35,14 +43,25 @@ public class TasksFragment extends Fragment implements TaskAdapter.OnTaskClickLi
|
|||
myEmail = UserManager.getInstance().getUserEmail();
|
||||
tabLayout = view.findViewById(R.id.task_tabs);
|
||||
recyclerView = view.findViewById(R.id.recycler_tasks);
|
||||
swipeRefresh = view.findViewById(R.id.swipe_refresh_tasks);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
setupTabs();
|
||||
|
||||
FloatingActionButton fab = view.findViewById(R.id.fab_add_task);
|
||||
fab.setOnClickListener(v -> {
|
||||
AddTaskBottomSheet dialog = new AddTaskBottomSheet();
|
||||
dialog.setOnTaskAddedListener(task -> {
|
||||
allTasks.add(0, task);
|
||||
saveAndRefresh();
|
||||
dialog.setOnTaskAddedListener(new AddTaskBottomSheet.OnTaskAddedListener() {
|
||||
@Override
|
||||
public void onTaskAdded(TaskItem task) {
|
||||
allTasks.add(0, task);
|
||||
saveAndSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskUpdated(TaskItem task) {
|
||||
saveAndSync();
|
||||
}
|
||||
});
|
||||
dialog.show(getChildFragmentManager(), "AddTask");
|
||||
});
|
||||
|
|
@ -53,12 +72,41 @@ public class TasksFragment extends Fragment implements TaskAdapter.OnTaskClickLi
|
|||
@Override public void onTabReselected(TabLayout.Tab tab) {}
|
||||
});
|
||||
|
||||
loadTasks();
|
||||
}
|
||||
swipeRefresh.setOnRefreshListener(this::fetchTasksFromServer);
|
||||
|
||||
private void loadTasks() {
|
||||
allTasks = CacheManager.getTasks(getContext());
|
||||
filterAndDisplay();
|
||||
fetchTasksFromServer();
|
||||
}
|
||||
|
||||
private void setupTabs() {
|
||||
tabLayout.removeAllTabs();
|
||||
tabLayout.addTab(tabLayout.newTab().setText("Mine"));
|
||||
tabLayout.addTab(tabLayout.newTab().setText("Fullførte"));
|
||||
tabLayout.addTab(tabLayout.newTab().setText("Tildelt andre"));
|
||||
if (UserManager.getInstance().isEditorOrAbove()) {
|
||||
tabLayout.addTab(tabLayout.newTab().setText("Alle"));
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchTasksFromServer() {
|
||||
swipeRefresh.setRefreshing(true);
|
||||
RetrofitClient.getApiService().getTasks().enqueue(new Callback<List<TaskItem>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<TaskItem>> call, Response<List<TaskItem>> response) {
|
||||
swipeRefresh.setRefreshing(false);
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
allTasks = response.body();
|
||||
CacheManager.saveTasks(getContext(), allTasks);
|
||||
filterAndDisplay();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onFailure(Call<List<TaskItem>> call, Throwable t) {
|
||||
swipeRefresh.setRefreshing(false);
|
||||
Toast.makeText(getContext(), "Kunne ikke synkronisere oppgaver", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void filterAndDisplay() {
|
||||
|
|
@ -66,21 +114,31 @@ public class TasksFragment extends Fragment implements TaskAdapter.OnTaskClickLi
|
|||
int selectedTab = tabLayout.getSelectedTabPosition();
|
||||
|
||||
for (TaskItem t : allTasks) {
|
||||
if (selectedTab == 0) { // MINE (Oppgaver tildelt meg som ikke er fullført av meg ennå)
|
||||
if (t.isUserParticipant(myEmail) && !t.getParticipantStatus(myEmail) && !t.isFullyCompleted()) {
|
||||
filtered.add(t);
|
||||
}
|
||||
} else if (selectedTab == 1) { // TILDELT ANDRE (Oppgaver jeg har laget, uansett om jeg er med selv)
|
||||
if (t.getCreatedByEmail().equals(myEmail) && !t.isFullyCompleted()) {
|
||||
filtered.add(t);
|
||||
}
|
||||
} else { // FULLFØRTE (Alt som er arkivert som ferdig)
|
||||
if (t.isFullyCompleted() || (t.isUserParticipant(myEmail) && t.getParticipantStatus(myEmail))) {
|
||||
filtered.add(t);
|
||||
}
|
||||
boolean isParticipant = t.isUserParticipant(myEmail);
|
||||
boolean isCreator = t.getCreatedByEmail().equalsIgnoreCase(myEmail);
|
||||
boolean iHaveDoneIt = t.getParticipantStatus(myEmail);
|
||||
boolean hasOtherParticipants = false;
|
||||
for (String email : t.getAssigneeStatus().keySet()) {
|
||||
if (!email.equalsIgnoreCase(myEmail)) { hasOtherParticipants = true; break; }
|
||||
}
|
||||
|
||||
switch (selectedTab) {
|
||||
case 0: // MINE
|
||||
if (isParticipant && !iHaveDoneIt && !t.isFullyCompleted()) filtered.add(t);
|
||||
break;
|
||||
case 1: // FULLFØRTE
|
||||
if (t.isFullyCompleted() || (isParticipant && iHaveDoneIt)) filtered.add(t);
|
||||
break;
|
||||
case 2: // TILDELT ANDRE
|
||||
if (isCreator && !t.isFullyCompleted() && hasOtherParticipants) filtered.add(t);
|
||||
break;
|
||||
case 3: // ALLE
|
||||
if (!t.isFullyCompleted()) filtered.add(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedTab == 1) Collections.sort(filtered, (t1, t2) -> Long.compare(t2.getDueDate(), t1.getDueDate()));
|
||||
else Collections.sort(filtered, (t1, t2) -> Long.compare(t1.getDueDate(), t2.getDueDate()));
|
||||
adapter = new TaskAdapter(filtered, this);
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
|
@ -88,15 +146,21 @@ public class TasksFragment extends Fragment implements TaskAdapter.OnTaskClickLi
|
|||
@Override
|
||||
public void onTaskClick(TaskItem task) {
|
||||
TaskDetailsBottomSheet sheet = new TaskDetailsBottomSheet(task, new TaskDetailsBottomSheet.OnTaskChangeListener() {
|
||||
@Override
|
||||
public void onTaskChanged() {
|
||||
saveAndRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskDeleted(TaskItem taskToDelete) {
|
||||
@Override public void onTaskChanged() { saveAndSync(); }
|
||||
@Override public void onTaskDeleted(TaskItem taskToDelete) {
|
||||
allTasks.remove(taskToDelete);
|
||||
saveAndRefresh();
|
||||
saveAndSync();
|
||||
}
|
||||
@Override public void onEditRequested(TaskItem taskToEdit) {
|
||||
AddTaskBottomSheet editDialog = new AddTaskBottomSheet();
|
||||
editDialog.setTaskToEdit(taskToEdit);
|
||||
editDialog.setOnTaskAddedListener(new AddTaskBottomSheet.OnTaskAddedListener() {
|
||||
@Override public void onTaskAdded(TaskItem task) {} // Ikke i bruk her
|
||||
@Override public void onTaskUpdated(TaskItem task) {
|
||||
saveAndSync();
|
||||
}
|
||||
});
|
||||
editDialog.show(getChildFragmentManager(), "EditTask");
|
||||
}
|
||||
});
|
||||
sheet.show(getChildFragmentManager(), "TaskDetails");
|
||||
|
|
@ -105,18 +169,22 @@ public class TasksFragment extends Fragment implements TaskAdapter.OnTaskClickLi
|
|||
@Override
|
||||
public void onStatusChanged(TaskItem task, boolean isDone) {
|
||||
task.setParticipantStatus(myEmail, isDone);
|
||||
|
||||
// Logikk: Hvis den som opprettet oppgaven merker den som ferdig,
|
||||
// regnes hele oppgaven som ferdig for alle (arkiveres).
|
||||
if (task.getCreatedByEmail().equals(myEmail) && isDone) {
|
||||
boolean hasOthers = false;
|
||||
for (String email : task.getAssigneeStatus().keySet()) {
|
||||
if (!email.equalsIgnoreCase(myEmail)) { hasOthers = true; break; }
|
||||
}
|
||||
if (task.getCreatedByEmail().equalsIgnoreCase(myEmail) && isDone && !hasOthers) {
|
||||
task.setFullyCompleted(true);
|
||||
}
|
||||
|
||||
saveAndRefresh();
|
||||
saveAndSync();
|
||||
}
|
||||
|
||||
private void saveAndRefresh() {
|
||||
private void saveAndSync() {
|
||||
CacheManager.saveTasks(getContext(), allTasks);
|
||||
filterAndDisplay();
|
||||
RetrofitClient.getApiService().syncTasks(allTasks).enqueue(new Callback<JsonElement>() {
|
||||
@Override public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {}
|
||||
@Override public void onFailure(Call<JsonElement> call, Throwable t) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -17,20 +17,47 @@ import retrofit2.http.PartMap;
|
|||
import retrofit2.http.Query;
|
||||
|
||||
public interface WordPressApiService {
|
||||
|
||||
// --- NYHETER ---
|
||||
@GET("wp-json/wp/v2/posts?per_page=10&_embed")
|
||||
Call<List<WpPost>> getPosts();
|
||||
@GET("wp-json/kbs/v1/forms/{id}")
|
||||
Call<GravityForm> getForm(@Path("id") int formId);
|
||||
|
||||
@POST("wp-json/gf/v2/forms/{id}/submissions")
|
||||
Call<JsonElement> submitForm(@Path("id") int formId, @Body FormSubmission submission);
|
||||
@GET("wp-json/wp/v2/posts?per_page=50&_embed")
|
||||
Call<List<WpPost>> getAllPosts();
|
||||
|
||||
|
||||
// --- AUTENTISERING & ENHET ---
|
||||
@POST("wp-json/kbs/v1/login")
|
||||
Call<LoginResponse> googleLogin(@Body LoginRequest request);
|
||||
|
||||
@POST("wp-json/kbs/v1/device/register")
|
||||
Call<JsonElement> registerDevice(@Body RegisterDeviceRequest request);
|
||||
|
||||
@GET("wp-json/kbs/v1/users")
|
||||
Call<List<User>> getUsersList();
|
||||
|
||||
|
||||
// --- KALENDER ---
|
||||
@GET("wp-json/kbs/v1/calendar/events")
|
||||
Call<List<CalendarEvent>> getCalendarEvents();
|
||||
|
||||
@POST("wp-json/kbs/v1/calendar/create")
|
||||
Call<JsonElement> createCalendarEvent(@Body CreateEventRequest request);
|
||||
|
||||
@POST("wp-json/kbs/v1/calendar/update")
|
||||
Call<JsonElement> updateCalendarEvent(@Body CreateEventRequest request);
|
||||
|
||||
@POST("wp-json/kbs/v1/calendar/delete")
|
||||
Call<JsonElement> deleteCalendarEvent(@Body CreateEventRequest request);
|
||||
|
||||
|
||||
// --- SKJEMAER (GRAVITY FORMS) ---
|
||||
@GET("wp-json/kbs/v1/forms")
|
||||
Call<List<GravityForm>> getFormsList();
|
||||
|
||||
@GET("wp-json/kbs/v1/forms/{id}")
|
||||
Call<GravityForm> getForm(@Path("id") int formId);
|
||||
|
||||
@Multipart
|
||||
@POST("wp-json/gf/v2/forms/{id}/submissions")
|
||||
Call<JsonElement> submitMultipartForm(
|
||||
|
|
@ -39,16 +66,6 @@ public interface WordPressApiService {
|
|||
@Part List<MultipartBody.Part> files
|
||||
);
|
||||
|
||||
@GET("wp-json/kbs/v1/calendar/events")
|
||||
Call<List<CalendarEvent>> getCalendarEvents();
|
||||
|
||||
@POST("wp-json/kbs/v1/calendar/create")
|
||||
Call<JsonElement> createCalendarEvent(@Body CreateEventRequest request);
|
||||
|
||||
// NYTT ENDEPUNKT
|
||||
@GET("wp-json/kbs/v1/users")
|
||||
Call<List<User>> getUsersList();
|
||||
|
||||
@GET("wp-json/gf/v2/entries")
|
||||
Call<GravityEntryResponse> getEntries(
|
||||
@Query("form_ids") int formId,
|
||||
|
|
@ -59,9 +76,8 @@ public interface WordPressApiService {
|
|||
@GET("wp-json/gf/v2/entries/{entry_id}")
|
||||
Call<JsonElement> getSingleEntry(@Path("entry_id") String entryId);
|
||||
|
||||
@GET("wp-json/wp/v2/posts?per_page=50&_embed")
|
||||
Call<List<WpPost>> getAllPosts();
|
||||
|
||||
// --- HÅNDBOK ---
|
||||
@GET("wp-json/kbs/v1/handbook")
|
||||
Call<List<HandbookItem>> getHandbookItems();
|
||||
|
||||
|
|
@ -71,12 +87,11 @@ public interface WordPressApiService {
|
|||
@GET("wp-json/kbs/v1/lookup-id")
|
||||
Call<JsonObject> lookupPageId(@Query("url") String url);
|
||||
|
||||
@POST("wp-json/kbs/v1/calendar/update")
|
||||
Call<JsonElement> updateCalendarEvent(@Body CreateEventRequest request);
|
||||
|
||||
@POST("wp-json/kbs/v1/calendar/delete")
|
||||
Call<JsonElement> deleteCalendarEvent(@Body CreateEventRequest request);
|
||||
// --- OPPGAVER (SYNKRONISERING) ---
|
||||
@GET("wp-json/kbs/v1/tasks")
|
||||
Call<List<TaskItem>> getTasks();
|
||||
|
||||
@POST("wp-json/kbs/v1/device/register")
|
||||
Call<JsonElement> registerDevice(@Body RegisterDeviceRequest request);
|
||||
@POST("wp-json/kbs/v1/tasks/sync")
|
||||
Call<JsonElement> syncTasks(@Body List<TaskItem> tasks);
|
||||
}
|
||||
|
|
@ -1,84 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:background="@color/white">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ny Oppgave"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_task_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Hva skal gjøres?"
|
||||
android:inputType="textCapSentences"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_task_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Beskrivelse (valgfritt)"
|
||||
android:inputType="textMultiLine"
|
||||
android:minLines="2"
|
||||
android:gravity="top"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="12dp">
|
||||
<Button
|
||||
android:id="@+id/btn_task_date"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sett frist" />
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:background="@color/white">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_date_preview"
|
||||
android:id="@+id/txt_sheet_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Frist: -"
|
||||
android:layout_marginStart="8dp"/>
|
||||
</LinearLayout>
|
||||
android:text="Ny Oppgave"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_task_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Hva skal gjøres?"
|
||||
android:inputType="textCapSentences"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_task_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Beskrivelse (valgfritt)"
|
||||
android:inputType="textMultiLine"
|
||||
android:minLines="2"
|
||||
android:gravity="top"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="12dp">
|
||||
<Button
|
||||
android:id="@+id/btn_task_date"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sett frist" />
|
||||
<TextView
|
||||
android:id="@+id/txt_date_preview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Frist: -"
|
||||
android:layout_marginStart="8dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="24dp">
|
||||
<Button
|
||||
android:id="@+id/btn_task_users"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Velg deltakere" />
|
||||
<TextView
|
||||
android:id="@+id/txt_users_preview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Kun meg"
|
||||
android:layout_marginStart="8dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="24dp">
|
||||
<Button
|
||||
android:id="@+id/btn_task_users"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/btn_save_task"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Velg deltakere" />
|
||||
<TextView
|
||||
android:id="@+id/txt_users_preview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Kun meg"
|
||||
android:layout_marginStart="8dp"/>
|
||||
android:text="Lagre Oppgave"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save_task"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Lagre Oppgave"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="@color/white"/>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
@ -65,13 +65,32 @@
|
|||
android:checked="true"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_delete_task"
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_owner_actions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Slett oppgave"
|
||||
android:backgroundTint="@color/kbs_logo_accent_red"
|
||||
android:textColor="@color/white"
|
||||
android:visibility="gone"/>
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_delete_task"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Slett"
|
||||
android:backgroundTint="@color/kbs_logo_accent_red"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_edit_task"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Endre"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginStart="8dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -1,44 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/white">
|
||||
|
||||
<!-- Knappen ligger nå helt øverst i fragmentet (under den globale toolbaren) -->
|
||||
<Button
|
||||
android:id="@+id/btn_add_calendar_event"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_full_calendar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="80dp" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_full_calendar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="+ Ny Kalenderhendelse"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="@color/white"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_view_calendar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ingen hendelser funnet"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<!-- NY FAB: Flytende knapp nederst til høyre -->
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_calendar_event"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="24dp"
|
||||
android:src="@android:drawable/ic_input_add"
|
||||
app:backgroundTint="@color/kbs_logo_blue"
|
||||
app:tint="@color/white"
|
||||
android:visibility="gone"
|
||||
android:contentDescription="Ny hendelse" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_full_calendar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_full_calendar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_view_calendar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ingen hendelser funnet"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone"/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
|
@ -5,31 +5,7 @@
|
|||
android:orientation="vertical"
|
||||
android:background="@color/kbs_very_light_blue">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:background="@android:color/white"
|
||||
android:elevation="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_back_news"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@android:drawable/ic_menu_revert"
|
||||
android:layout_centerVertical="true"
|
||||
android:contentDescription="Tilbake"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Siste nytt"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@android:color/black"
|
||||
android:layout_centerInParent="true"/>
|
||||
</RelativeLayout>
|
||||
<!-- Redundant header er fjernet. Kun kategorilisten og nyhetslisten er igjen. -->
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_categories"
|
||||
|
|
|
|||
|
|
@ -13,21 +13,7 @@
|
|||
android:background="@color/white"
|
||||
app:tabSelectedTextColor="@color/kbs_logo_blue"
|
||||
app:tabIndicatorColor="@color/kbs_logo_blue">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Mine" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tildelt andre" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Fullførte" />
|
||||
<!-- Faner legges til programmatisk i TasksFragment.java -->
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
|
|
|
|||
10
app/src/main/res/layout/item_home_empty_tasks.xml
Normal file
10
app/src/main/res/layout/item_home_empty_tasks.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ingen oppgaver tildelt"
|
||||
android:textColor="@color/kbs_muted_blue_gray"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="italic"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingVertical="8dp" />
|
||||
|
|
@ -44,6 +44,15 @@
|
|||
android:textSize="12sp"
|
||||
android:textColor="@color/kbs_muted_blue_gray" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/task_creator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tildelt av: -"
|
||||
android:textSize="11sp"
|
||||
android:textColor="@color/kbs_logo_blue"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/task_progress"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -51,7 +60,7 @@
|
|||
android:text="Fremdrift: 0/0"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="italic"
|
||||
android:textColor="@color/kbs_logo_blue"
|
||||
android:textColor="@color/kbs_muted_blue_gray"
|
||||
android:layout_marginTop="2dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue