Før lenker i detaljvisning av kalenderoppføringer
This commit is contained in:
parent
5497e68110
commit
845ccf22c2
10 changed files with 1143 additions and 419 deletions
|
|
@ -59,6 +59,16 @@
|
|||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<!-- Standard ikon for Firebase varsler -->
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/ic_stat_kbs" />
|
||||
|
||||
<!-- Standard farge for Firebase varsler (KBS Blå) -->
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_color"
|
||||
android:resource="@color/kbs_logo_blue" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -12,6 +12,7 @@ import android.os.Build;
|
|||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.content.ContextCompat; // <-- Denne manglet
|
||||
|
||||
public class AlarmReceiver extends BroadcastReceiver {
|
||||
|
||||
|
|
@ -48,7 +49,8 @@ public class AlarmReceiver extends BroadcastReceiver {
|
|||
);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_launcher_foreground) // Pass på at du har et ikon her, ellers bruk R.mipmap.ic_launcher
|
||||
.setSmallIcon(R.drawable.ic_stat_kbs)
|
||||
.setColor(ContextCompat.getColor(context, R.color.kbs_logo_blue)) // Setter KBS-blå farge på ikonet
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
|
|
|
|||
95
app/src/main/java/com/kbs/kbsintranett/CacheManager.java
Normal file
95
app/src/main/java/com/kbs/kbsintranett/CacheManager.java
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CacheManager {
|
||||
private static final String FILE_CALENDAR = "cache_calendar.json";
|
||||
private static final String FILE_NEWS = "cache_news.json";
|
||||
private static final String FILE_HANDBOOK = "cache_handbook.json";
|
||||
|
||||
private static final String TAG = "CacheManager";
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
// --- KALENDER ---
|
||||
public static void saveCalendarEvents(Context context, List<CalendarEvent> events) {
|
||||
saveList(context, FILE_CALENDAR, events);
|
||||
}
|
||||
|
||||
public static List<CalendarEvent> getCachedCalendarEvents(Context context) {
|
||||
Type type = new TypeToken<List<CalendarEvent>>() {}.getType();
|
||||
List<CalendarEvent> list = loadList(context, FILE_CALENDAR, type);
|
||||
return list != null ? list : new ArrayList<>();
|
||||
}
|
||||
|
||||
// --- NYHETER ---
|
||||
public static void saveNewsPosts(Context context, List<WpPost> posts) {
|
||||
saveList(context, FILE_NEWS, posts);
|
||||
}
|
||||
|
||||
public static List<WpPost> getCachedNewsPosts(Context context) {
|
||||
Type type = new TypeToken<List<WpPost>>() {}.getType();
|
||||
List<WpPost> list = loadList(context, FILE_NEWS, type);
|
||||
return list != null ? list : new ArrayList<>();
|
||||
}
|
||||
|
||||
// --- HÅNDBOK ---
|
||||
public static void saveHandbookItems(Context context, List<HandbookItem> items) {
|
||||
saveList(context, FILE_HANDBOOK, items);
|
||||
}
|
||||
|
||||
public static List<HandbookItem> getCachedHandbookItems(Context context) {
|
||||
Type type = new TypeToken<List<HandbookItem>>() {}.getType();
|
||||
List<HandbookItem> list = loadList(context, FILE_HANDBOOK, type);
|
||||
return list != null ? list : new ArrayList<>();
|
||||
}
|
||||
|
||||
// --- GENERISKE HJELPEMETODER ---
|
||||
|
||||
private static <T> void saveList(Context context, String filename, List<T> list) {
|
||||
if (context == null || list == null) return;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
String json = gson.toJson(list);
|
||||
FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
|
||||
fos.write(json.getBytes());
|
||||
fos.close();
|
||||
Log.d(TAG, "Lagret cache til " + filename);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Feil ved lagring av cache: " + filename, e);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private static <T> List<T> loadList(Context context, String filename, Type type) {
|
||||
if (context == null) return null;
|
||||
File file = new File(context.getFilesDir(), filename);
|
||||
if (!file.exists()) return null;
|
||||
|
||||
try {
|
||||
FileInputStream fis = context.openFileInput(filename);
|
||||
InputStreamReader isr = new InputStreamReader(fis);
|
||||
BufferedReader bufferedReader = new BufferedReader(isr);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
fis.close();
|
||||
return gson.fromJson(sb.toString(), type);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Feil ved lesing av cache: " + filename, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import android.view.ViewGroup;
|
|||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -89,7 +90,6 @@ public class HomeFragment extends Fragment {
|
|||
btnCreateEvent.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// KALENDER: Standard scrolling (slik at man kan scrolle i vinduet på 230dp)
|
||||
calendarRecycler = view.findViewById(R.id.recycler_calendar);
|
||||
calendarRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
calendarRecycler.setAdapter(new CalendarAdapter(new ArrayList<>(), event -> {}));
|
||||
|
|
@ -105,7 +105,6 @@ public class HomeFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// NYHETER: Nested scrolling disabled (skal vises i full høyde under kalenderen)
|
||||
newsRecycler = view.findViewById(R.id.recycler_news);
|
||||
newsRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
newsRecycler.setNestedScrollingEnabled(false);
|
||||
|
|
@ -167,11 +166,42 @@ public class HomeFragment extends Fragment {
|
|||
List<CalendarEvent> apiEvents = new ArrayList<>();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
apiEvents = response.body();
|
||||
|
||||
CacheManager.saveCalendarEvents(getContext(), apiEvents);
|
||||
|
||||
for (CalendarEvent e : apiEvents) {
|
||||
CalendarManager.formatEventForUI(e);
|
||||
}
|
||||
} else {
|
||||
apiEvents = CacheManager.getCachedCalendarEvents(getContext());
|
||||
for (CalendarEvent e : apiEvents) CalendarManager.formatEventForUI(e);
|
||||
if (!apiEvents.isEmpty()) {
|
||||
Toast.makeText(getContext(), "Server utilgjengelig. Viser lagret kalender.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
updateCalendarUI(recyclerView, apiEvents, deviceEvents);
|
||||
checkLoadingComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
||||
if (!isAdded()) return;
|
||||
|
||||
List<CalendarEvent> cachedApiEvents = CacheManager.getCachedCalendarEvents(getContext());
|
||||
for (CalendarEvent e : cachedApiEvents) CalendarManager.formatEventForUI(e);
|
||||
|
||||
if (!cachedApiEvents.isEmpty()) {
|
||||
Toast.makeText(getContext(), "Ingen nettverk. Viser lagret kalender.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
updateCalendarUI(recyclerView, cachedApiEvents, deviceEvents);
|
||||
checkLoadingComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateCalendarUI(RecyclerView recyclerView, List<CalendarEvent> apiEvents, List<CalendarEvent> deviceEvents) {
|
||||
List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
||||
List<CalendarEvent> upcomingEvents = new ArrayList<>();
|
||||
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
||||
|
|
@ -183,7 +213,6 @@ public class HomeFragment extends Fragment {
|
|||
}
|
||||
|
||||
List<CalendarEvent> topEvents = new ArrayList<>();
|
||||
// ENDRET: Grensen er satt tilbake til 5
|
||||
for(int i=0; i<Math.min(upcomingEvents.size(), 5); i++) {
|
||||
topEvents.add(upcomingEvents.get(i));
|
||||
}
|
||||
|
|
@ -193,29 +222,6 @@ public class HomeFragment extends Fragment {
|
|||
sheet.setOnEventChangeListener(HomeFragment.this::refreshData);
|
||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||
}));
|
||||
|
||||
checkLoadingComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
||||
if (!isAdded()) return;
|
||||
|
||||
if (!deviceEvents.isEmpty()) {
|
||||
List<CalendarEvent> topEvents = new ArrayList<>();
|
||||
// ENDRET: Grensen er satt tilbake til 5 (Fallback)
|
||||
for(int i=0; i<Math.min(deviceEvents.size(), 5); i++) topEvents.add(deviceEvents.get(i));
|
||||
recyclerView.setAdapter(new CalendarAdapter(topEvents, event -> {
|
||||
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||
}));
|
||||
} else {
|
||||
recyclerView.setAdapter(new CalendarAdapter(new ArrayList<>(), null));
|
||||
}
|
||||
|
||||
checkLoadingComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fetchNewsFromWordpress(RecyclerView recyclerView) {
|
||||
|
|
@ -225,39 +231,58 @@ public class HomeFragment extends Fragment {
|
|||
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
||||
if (getContext() == null) return;
|
||||
|
||||
List<WpPost> postsToShow = new ArrayList<>();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
List<WpPost> wpPosts = response.body();
|
||||
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 : wpPosts) {
|
||||
try {
|
||||
Date date = rawFormat.parse(post.date);
|
||||
post.date = targetFormat.format(date);
|
||||
} catch (Exception e) {}
|
||||
postsToShow = response.body();
|
||||
CacheManager.saveNewsPosts(getContext(), postsToShow);
|
||||
} else {
|
||||
postsToShow = CacheManager.getCachedNewsPosts(getContext());
|
||||
if (!postsToShow.isEmpty()) {
|
||||
Toast.makeText(getContext(), "Server utilgjengelig. Viser lagrede nyheter.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
NewsAdapter adapter = new NewsAdapter(wpPosts, post -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("post_data", post);
|
||||
Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsDetail, bundle);
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
updateNewsUI(recyclerView, postsToShow);
|
||||
checkLoadingComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
||||
if (getContext() == null) return;
|
||||
recyclerView.setAdapter(new NewsAdapter(new ArrayList<>(), null));
|
||||
|
||||
List<WpPost> cachedPosts = CacheManager.getCachedNewsPosts(getContext());
|
||||
if (!cachedPosts.isEmpty()) {
|
||||
Toast.makeText(getContext(), "Ingen nettverk. Viser lagrede nyheter.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
updateNewsUI(recyclerView, cachedPosts);
|
||||
checkLoadingComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateNewsUI(RecyclerView recyclerView, 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 {
|
||||
Date date = rawFormat.parse(post.date);
|
||||
post.date = targetFormat.format(date);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
NewsAdapter adapter = new NewsAdapter(posts, post -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("post_data", post);
|
||||
Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsDetail, bundle);
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void startNotificationWorker() {
|
||||
PeriodicWorkRequest notifRequest =
|
||||
new PeriodicWorkRequest.Builder(NotificationWorker.class, 15, TimeUnit.MINUTES)
|
||||
|
|
|
|||
BIN
app/src/main/res/drawable-hdpi/ic_stat_kbs.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_stat_kbs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 630 B |
BIN
app/src/main/res/drawable-mdpi/ic_stat_kbs.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_stat_kbs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 395 B |
BIN
app/src/main/res/drawable-xhdpi/ic_stat_kbs.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_stat_kbs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 895 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_kbs.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_kbs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_stat_kbs.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_stat_kbs.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
1078
hele_prosjektet.txt
1078
hele_prosjektet.txt
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue