diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0d53ad3..e48c0b0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -57,6 +57,18 @@
android:name=".activities.InterestsActivity"
android:theme="@style/Theme.Capture.NoActionBar" />
+
+
+
+
+
+
+
+
{
+ // Success - post created and image uploaded
String postId = documentReference.getId();
Log.d("CameraFragment", "Post saved with ID: " + postId);
Toast.makeText(requireContext(), "Post uploaded successfully!", Toast.LENGTH_SHORT).show();
+ // Update the home screen widget
+ updateWidget();
+
+ // For testing: verify the post was saved by reading it back
FirebaseFirestore.getInstance().collection("posts").document(postId)
.get()
.addOnSuccessListener(postSnapshot -> {
@@ -463,4 +472,24 @@ private void resetCameraAfterPost() {
}
}
}
+
+ /**
+ * Update the home screen widget with the latest post
+ */
+ private void updateWidget() {
+ Intent intent = new Intent(requireContext(), com.pineapple.capture.widget.LatestPostWidget.class);
+ intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+
+ // Use AppWidgetManager to get the widget IDs
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(requireContext());
+ int[] appWidgetIds = appWidgetManager.getAppWidgetIds(
+ new ComponentName(requireContext(), com.pineapple.capture.widget.LatestPostWidget.class));
+
+ // Add widget IDs to the intent
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+
+ // Send broadcast to update widgets
+ requireContext().sendBroadcast(intent);
+ Log.d("CameraFragment", "Widget update broadcast sent");
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/pineapple/capture/widget/LatestPostWidget.java b/app/src/main/java/com/pineapple/capture/widget/LatestPostWidget.java
new file mode 100644
index 0000000..d928644
--- /dev/null
+++ b/app/src/main/java/com/pineapple/capture/widget/LatestPostWidget.java
@@ -0,0 +1,177 @@
+package com.pineapple.capture.widget;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.View;
+import android.widget.RemoteViews;
+import android.os.Bundle;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.target.AppWidgetTarget;
+import com.bumptech.glide.request.transition.Transition;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.Query;
+import com.google.firebase.firestore.QueryDocumentSnapshot;
+import com.pineapple.capture.MainActivity;
+import com.pineapple.capture.R;
+import com.pineapple.capture.feed.FeedItem;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class LatestPostWidget extends AppWidgetProvider {
+
+ private static final String TAG = "LatestPostWidget";
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ // There may be multiple widgets active, so update all of them
+ for (int appWidgetId : appWidgetIds) {
+ updateAppWidget(context, appWidgetManager, appWidgetId);
+ }
+ }
+
+ private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_latest_post);
+
+ // Show loading state - hide post views, show empty view with loading text
+ views.setViewVisibility(R.id.widget_empty_view, View.VISIBLE);
+ views.setTextViewText(R.id.widget_empty_view, "Loading...");
+
+ // Set up click intent for the widget
+ Intent intent = new Intent(context, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+ views.setOnClickPendingIntent(R.id.widget_post_image, pendingIntent);
+
+ // Update the widget initially with loading state
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+
+ // Fetch the latest post from Firestore
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ db.collection("posts")
+ .orderBy("timestamp", Query.Direction.DESCENDING)
+ .limit(1)
+ .get()
+ .addOnSuccessListener(queryDocumentSnapshots -> {
+ if (!queryDocumentSnapshots.isEmpty()) {
+ for (QueryDocumentSnapshot document : queryDocumentSnapshots) {
+ FeedItem latestPost = document.toObject(FeedItem.class);
+ latestPost.setId(document.getId());
+
+ // Update widget with post data
+ updateWidgetWithPost(context, appWidgetManager, appWidgetId, latestPost);
+ return;
+ }
+ } else {
+ // No posts found
+ views.setViewVisibility(R.id.widget_empty_view, View.VISIBLE);
+ views.setTextViewText(R.id.widget_empty_view, "No posts available");
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
+ })
+ .addOnFailureListener(e -> {
+ Log.e(TAG, "Error fetching latest post", e);
+ views.setViewVisibility(R.id.widget_empty_view, View.VISIBLE);
+ views.setTextViewText(R.id.widget_empty_view, "Error loading post");
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ });
+ }
+
+ private void updateWidgetWithPost(Context context, AppWidgetManager appWidgetManager,
+ int appWidgetId, FeedItem post) {
+ // Create a RemoteViews object
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_latest_post);
+
+ // Hide empty view
+ views.setViewVisibility(R.id.widget_empty_view, View.GONE);
+
+ // Set caption
+ if (post.getContent() != null && !post.getContent().isEmpty()) {
+ views.setTextViewText(R.id.widget_post_caption, post.getContent());
+ views.setViewVisibility(R.id.widget_post_caption, View.VISIBLE);
+ } else {
+ views.setViewVisibility(R.id.widget_post_caption, View.GONE);
+ }
+
+ // Set username
+ views.setTextViewText(R.id.widget_username, post.getUsername() != null ?
+ post.getUsername() : "Anonymous");
+
+ // Set up click intent to open the app
+ Intent intent = new Intent(context, MainActivity.class);
+ intent.putExtra("post_id", post.getId());
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+ views.setOnClickPendingIntent(R.id.widget_post_image, pendingIntent);
+
+ // First update with what we have (without images)
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+
+ // Load images in background thread
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Handler handler = new Handler(Looper.getMainLooper());
+
+ executor.execute(() -> {
+ try {
+ // Load post image with Glide in background thread
+ if (post.getImageUrl() != null && !post.getImageUrl().isEmpty()) {
+ try {
+ Bitmap bitmap = Glide.with(context.getApplicationContext())
+ .asBitmap()
+ .load(post.getImageUrl())
+ .submit(400, 400) // Limit size to prevent OOM
+ .get();
+
+ views.setImageViewBitmap(R.id.widget_post_image, bitmap);
+ } catch (Exception e) {
+ Log.e(TAG, "Error loading post image", e);
+ }
+ }
+
+ // Load user avatar with Glide in background thread
+ if (post.getProfilePictureUrl() != null && !post.getProfilePictureUrl().isEmpty()) {
+ try {
+ Bitmap avatarBitmap = Glide.with(context.getApplicationContext())
+ .asBitmap()
+ .load(post.getProfilePictureUrl())
+ .circleCrop()
+ .submit(80, 80) // Small size for avatar
+ .get();
+
+ views.setImageViewBitmap(R.id.widget_user_avatar, avatarBitmap);
+ } catch (Exception e) {
+ Log.e(TAG, "Error loading avatar image", e);
+ }
+ }
+
+ // Update widget with images on main thread
+ handler.post(() -> {
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ });
+ } catch (Exception e) {
+ Log.e(TAG, "Error in background loading", e);
+ }
+ });
+ }
+
+ @Override
+ public void onEnabled(Context context) {
+ // Called when the first widget is created
+ }
+
+ @Override
+ public void onDisabled(Context context) {
+ // Called when the last widget is disabled
+
+ // Shutdown the executor service if needed
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/widget_background.xml b/app/src/main/res/drawable/widget_background.xml
new file mode 100644
index 0000000..5bced41
--- /dev/null
+++ b/app/src/main/res/drawable/widget_background.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/widget_preview.xml b/app/src/main/res/drawable/widget_preview.xml
new file mode 100644
index 0000000..ba9ac3f
--- /dev/null
+++ b/app/src/main/res/drawable/widget_preview.xml
@@ -0,0 +1,39 @@
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/widget_latest_post.xml b/app/src/main/res/layout/widget_latest_post.xml
new file mode 100644
index 0000000..78ea403
--- /dev/null
+++ b/app/src/main/res/layout/widget_latest_post.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/latest_post_widget_info.xml b/app/src/main/res/xml/latest_post_widget_info.xml
new file mode 100644
index 0000000..826ddfb
--- /dev/null
+++ b/app/src/main/res/xml/latest_post_widget_info.xml
@@ -0,0 +1,11 @@
+
+
+
\ No newline at end of file