Skip to content
This repository has been archived by the owner on Mar 28, 2024. It is now read-only.

Commit

Permalink
Add home widget feature displaying the first four missing anime
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziedelth committed Aug 17, 2023
1 parent ebbdde9 commit 3e80ec3
Show file tree
Hide file tree
Showing 15 changed files with 263 additions and 8 deletions.
1 change: 1 addition & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,5 @@ flutter {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
}
8 changes: 8 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@
</intent-filter>
</activity>

<receiver android:name="HomeWidgetProvider" android:exported="false" android:label="Watchlist">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/home_widget_provider" />
</receiver>

<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-5658764393995798~7443712880"/>
Expand Down
74 changes: 74 additions & 0 deletions android/app/src/main/kotlin/fr/ziedelth/jais/HomeWidgetProvider.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package fr.ziedelth.jais

import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.SharedPreferences
import android.graphics.BitmapFactory
import android.net.Uri
import android.view.View
import android.widget.RemoteViews

import es.antonborri.home_widget.HomeWidgetBackgroundIntent
import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetProvider

class HomeWidgetProvider : HomeWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, widgetData: SharedPreferences) {
appWidgetIds.forEach { widgetId ->
val views = RemoteViews(context.packageName, R.layout.home_widget_layout).apply {
// Open App on Widget Click
val pendingIntent = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java)
setOnClickPendingIntent(R.id.home_widget_container, pendingIntent)

// Show Images saved with `renderFlutterWidget`
val image1 = widgetData.getString("image0", null)

if (image1 != null) {
setImageViewBitmap(R.id.widget_img1, BitmapFactory.decodeFile(image1))
setViewVisibility(R.id.widget_img1, View.VISIBLE)
} else {
setViewVisibility(R.id.widget_img1, View.GONE)
}

val image2 = widgetData.getString("image1", null)

if (image2 != null) {
setImageViewBitmap(R.id.widget_img2, BitmapFactory.decodeFile(image2))
setViewVisibility(R.id.widget_img2, View.VISIBLE)
} else {
setViewVisibility(R.id.widget_img2, View.GONE)
}

val image3 = widgetData.getString("image2", null)

if (image3 != null) {
setImageViewBitmap(R.id.widget_img3, BitmapFactory.decodeFile(image3))
setViewVisibility(R.id.widget_img3, View.VISIBLE)
} else {
setViewVisibility(R.id.widget_img3, View.GONE)
}

val image4 = widgetData.getString("image3", null)

if (image4 != null) {
setImageViewBitmap(R.id.widget_img4, BitmapFactory.decodeFile(image4))
setViewVisibility(R.id.widget_img4, View.VISIBLE)
} else {
setViewVisibility(R.id.widget_img4, View.GONE)
}

// Nothing in your watchlist yet
if (image1 != null || image2 != null || image3 != null || image4 != null) {
setViewVisibility(R.id.widget_nothing, View.GONE)
} else {
setViewVisibility(R.id.widget_nothing, View.VISIBLE)
setTextViewText(R.id.widget_nothing, "Nothing in your watchlist yet")
}
}

appWidgetManager.updateAppWidget(widgetId, views)
}
}
}
5 changes: 5 additions & 0 deletions android/app/src/main/res/drawable/home_widget_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?android:attr/colorBackground"/>
<corners android:radius="16dp"/>
</shape>
47 changes: 47 additions & 0 deletions android/app/src/main/res/layout/home_widget_layout.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:orientation="horizontal"
android:background="@drawable/home_widget_background"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:padding="8dp"
android:id="@+id/home_widget_container">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/widget_img1"
android:visibility="gone"/>

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/widget_img2"
android:visibility="gone"/>

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/widget_img3"
android:visibility="gone"/>

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/widget_img4"
android:visibility="gone"/>

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:text="Nothing in your watchlist yet"
android:gravity="center"
android:id="@+id/widget_nothing"/>
</LinearLayout>
9 changes: 9 additions & 0 deletions android/app/src/main/res/xml/home_widget_provider.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="80dp"
android:minHeight="40dp"
android:updatePeriodMillis="1800000"
android:initialLayout="@layout/home_widget_layout"
android:resizeMode="horizontal"
android:widgetCategory="home_screen">
</appwidget-provider>
7 changes: 4 additions & 3 deletions lib/controllers/animes/missing_anime_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import 'package:jais/widgets/animes/missing_anime_widget.dart';

class MissingAnimeController extends DataController<MissingAnime,
MissingAnimeLoaderWidget, MissingAnimeWidget> with AbstractFilter {
MissingAnimeController({required super.notifyListenersCallback})
: super(
limit: 12,
MissingAnimeController({
required super.notifyListenersCallback,
super.limit = 12,
}) : super(
loadingWidget: const MissingAnimeLoaderWidget(),
fromJson: (json) => MissingAnime.fromJson(json),
toWidget: (anime) => MissingAnimeWidget(missingAnime: anime),
Expand Down
5 changes: 5 additions & 0 deletions lib/controllers/app_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:jais/controllers/datas/collection_data_controller.dart';
import 'package:jais/controllers/filter_controller.dart';
import 'package:jais/controllers/home_widget_controller.dart';
import 'package:jais/controllers/url_controller.dart';
import 'package:jais/firebase_options.dart';
import 'package:jais/utils.dart';
Expand All @@ -13,6 +14,8 @@ class AppController with ChangeNotifier {
CollectionDataController('animeWatchlist');
static final CollectionDataController seen =
CollectionDataController('episodesSeen');
static final HomeWidgetController homeWidgetController =
HomeWidgetController();

bool _inProgress = true;
bool _hasInternet = false;
Expand All @@ -23,6 +26,7 @@ class AppController with ChangeNotifier {

AppController() {
checkInternetConnection();
homeWidgetController.init();
}

Future<void> checkInternetConnection() async {
Expand All @@ -48,5 +52,6 @@ class AppController with ChangeNotifier {

await FirebaseMessaging.instance.requestPermission();
await FirebaseMessaging.instance.subscribeToTopic('all');
await homeWidgetController.notify();
}
}
4 changes: 2 additions & 2 deletions lib/controllers/episode_tab_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class EpisodeTabController with ChangeNotifier {
episodeController.reset();
notify();

missingAnimeController.load().whenComplete(() => notify());
episodeController.load().whenComplete(() => notify());
missingAnimeController.load().whenComplete(notify);
episodeController.load().whenComplete(notify);
}

void notify() {
Expand Down
76 changes: 76 additions & 0 deletions lib/controllers/home_widget_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:home_widget/home_widget.dart';
import 'package:jais/controllers/animes/missing_anime_controller.dart';
import 'package:jais/controllers/logger.dart';
import 'package:jais/models/anime.dart';
import 'package:jais/utils.dart';
import 'package:jais/widgets/animes/anime_image.dart';
import 'package:jais/widgets/animes/missing_anime_widget.dart';

class HomeWidgetController {
late MissingAnimeController missingAnimeController;
static const int limit = 4;

void init() {
missingAnimeController =
MissingAnimeController(limit: 4, notifyListenersCallback: () {});
}

Future<void> notify() async {
missingAnimeController.reset();
await missingAnimeController.load();

try {
final List<AnimeImage> animeImages = [];

for (int i = 0; i < limit; i++) {
final MissingAnimeWidget? missingAnimeWidget =
missingAnimeController.list.elementAtOrNull(i)
as MissingAnimeWidget?;

if (missingAnimeWidget == null) {
break;
}

final Anime anime = missingAnimeWidget.missingAnime.anime;

animeImages.add(
AnimeImage(
anime: anime,
width: Const.missingAnimeImageWith * 10,
height: Const.missingAnimeImageHeight * 10,
radius: 360,
),
);
}

info(
'EpisodeTabController',
'updateHomeWidget() - ${animeImages.length} images',
);

if (animeImages.isNotEmpty) {
await Future.wait([
for (final AnimeImage image in animeImages)
HomeWidget.renderFlutterWidget(
image,
logicalSize: const Size(
Const.missingAnimeImageWith * 10,
Const.missingAnimeImageHeight * 10,
),
key: 'image${animeImages.indexOf(image)}',
),
]);
} else {
await Future.wait([
for (int i = 0; i < limit; i++)
HomeWidget.saveWidgetData('image$i', null),
]);
}

await HomeWidget.updateWidget(name: 'HomeWidgetProvider');
} catch (exception, stackTrace) {
error('EpisodeTabController', '$exception', exception, stackTrace);
}
}
}
16 changes: 14 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:home_widget/home_widget.dart';
import 'package:jais/controllers/animes/anime_detail_controller.dart';
import 'package:jais/controllers/animes/anime_diary_controller.dart';
import 'package:jais/controllers/animes/anime_search_controller.dart';
Expand All @@ -24,11 +25,22 @@ Future<void> main() async {
);
}

class MyApp extends StatelessWidget {
class MyApp extends StatefulWidget {
const MyApp({super.key});

@override
State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
static const Color _mainWhiteThemeColor = Color(0xFFa32d26);
static const Color _mainDarkThemeColor = Color(0xFFfde5c9);

const MyApp({super.key});
@override
void initState() {
super.initState();
HomeWidget.setAppGroupId('jais');
}

@override
Widget build(BuildContext context) {
Expand Down
1 change: 1 addition & 0 deletions lib/widgets/episodes/episode_see_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class _EpisodeSeeWidgetState extends State<EpisodeSeeWidget> {
}

setState(() {});
await AppController.homeWidgetController.notify();
},
child: Icon(
isWatched ? Icons.visibility : Icons.visibility_off,
Expand Down
3 changes: 3 additions & 0 deletions lib/widgets/watchlist_button.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:jais/controllers/app_controller.dart';

class WatchlistButton extends StatefulWidget {
final bool inWatchlist;
Expand Down Expand Up @@ -47,6 +48,8 @@ class _WatchlistButtonState extends State<WatchlistButton> {
setState(() {
_inWatchlist = !_inWatchlist;
});

await AppController.homeWidgetController.notify();
},
);
}
Expand Down
9 changes: 9 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,15 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.1"
home_widget:
dependency: "direct main"
description:
path: "."
ref: e02d386487bf47324fb7ca5112eccb345a26cf06
resolved-ref: e02d386487bf47324fb7ca5112eccb345a26cf06
url: "https://github.com/Ziedelth/flutter_home_widget.git"
source: git
version: "0.3.0"
html:
dependency: transitive
description:
Expand Down
6 changes: 5 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ dependencies:
flutter:
sdk: flutter
flutter_svg: ^2.0.7
home_widget:
git:
url: https://github.com/Ziedelth/flutter_home_widget.git
ref: e02d386487bf47324fb7ca5112eccb345a26cf06
http: ^0.13.6
intl: ^0.18.1
json_annotation: ^4.8.1
Expand All @@ -25,9 +29,9 @@ dependencies:

dev_dependencies:
build_runner: ^2.4.6
flutterando_metrics: ^5.7.6
flutter_launcher_icons: ^0.13.1
flutter_native_splash: ^2.3.2
flutterando_metrics: ^5.7.6
json_serializable: ^6.7.1
lint: ^2.1.2

Expand Down

0 comments on commit 3e80ec3

Please sign in to comment.