29-02-1403 / Rhmn / Widget Android Created.

This commit is contained in:
OkaykOrhmn 2024-05-18 17:59:23 +03:30
parent d4afdeb688
commit e609feab7b
35 changed files with 1438 additions and 606 deletions

View File

@ -75,6 +75,9 @@ android {
disable 'InvalidPackage'
checkReleaseBuilds false
}
buildFeatures {
viewBinding true
}
}
flutter {
@ -84,4 +87,7 @@ flutter {
dependencies {
implementation platform('com.google.firebase:firebase-bom:29.1.0')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.google.code.gson:gson:2.10.1'
// implementation 'com.github.bumptech.glide:glide:4.16.0'
implementation 'com.squareup.picasso:picasso:2.8'
}

View File

@ -1,56 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.didvan.didvanapp">
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
<application
android:label="Didvan"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:label="Didvan"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true">
<receiver
android:name=".FavWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/favourite_widget_info" />
</receiver>
<receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"
android:exported="true">
<intent-filter>
<action android:name="es.antonborri.home_widget.action.BACKGROUND" />
</intent-filter>
</receiver>
<service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/>
android:requestLegacyExternalStorage="true">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:showOnLockScreen="true"
android:showWhenLocked="true"
android:theme="@style/LaunchTheme"
android:turnScreenOn="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
<!--
Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
to determine the Window background behind the Flutter UI.
-->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:resource="@style/NormalTheme" />
<!-- Displays an Android View that continues showing the launch screen
<!--
Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
Flutter's first frame.
-->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
<service
android:name=".MyFirebaseMessagingService"
@ -59,9 +89,6 @@
<action android:name="com.google.firebase.messaging.RECEIVE" />
</intent-filter>
</service>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
</application>
</manifest>

View File

@ -0,0 +1,113 @@
package com.didvan.didvanapp
import android.annotation.SuppressLint
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.widget.RemoteViews
import com.squareup.picasso.Picasso
import com.squareup.picasso.Transformation
import es.antonborri.home_widget.HomeWidgetBackgroundIntent
import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetProvider
/**
* Implementation of App Widget functionality.
*/
class FavWidget : HomeWidgetProvider() {
@SuppressLint("RemoteViewLayout")
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
widgetData: SharedPreferences
) {
appWidgetIds.forEach { widgetId ->
val views = RemoteViews(context.packageName, R.layout.favourite_widget).apply {
// Open App on Widget Click
val pendingIntent = HomeWidgetLaunchIntent.getActivity(
context,
MainActivity::class.java
)
setOnClickPendingIntent(R.id.logo_btn, pendingIntent)
val responses: ArrayList<WidgetResponse> = ArrayList();
val token = widgetData.getString("token", "").toString()
for (i in 0..2) {
responses.add(
WidgetResponse(
id = widgetData.getString("id${i + 1}", "")?.toInt() ?: 0,
title = widgetData.getString("title${i + 1}", "").toString(),
createdAt = widgetData.getString("createdAt${i + 1}", "").toString(),
type = widgetData.getString("type${i + 1}", "").toString(),
link = widgetData.getString("link${i + 1}", "").toString(),
category = widgetData.getString("category${i + 1}", "").toString(),
image = widgetData.getString("image${i + 1}", "").toString(),
)
)
}
setTextViewText(R.id.first_title, responses[0].title.toString())
setTextViewText(R.id.middle_title, responses[1].title.toString())
setTextViewText(R.id.last_title, responses[2].title.toString())
//
setTextViewText(R.id.first_tag, responses[0].category)
setTextViewText(R.id.middle_tag, responses[1].category)
setTextViewText(R.id.last_tag, responses[2].category)
setTextViewText(R.id.first_duration, responses[0].createdAt)
setTextViewText(R.id.middle_duration, responses[1].createdAt)
setTextViewText(R.id.last_duration, responses[2].createdAt)
Picasso.get()
.load("https://api.didvan.app${responses[0].image}?accessToken=${token}")
.transform(RoundedTransformation(50, 0))
.into(this, R.id.first_image, appWidgetIds);
Picasso.get()
.load("https://api.didvan.app${responses[1].image}?accessToken=${token}")
.transform(RoundedTransformation(50, 0))
.into(this, R.id.middle_image, appWidgetIds);
Picasso.get()
.load("https://api.didvan.app${responses[2].image}?accessToken=${token}")
.transform(RoundedTransformation(50, 0))
.into(this, R.id.last_image, appWidgetIds);
// Pending intent to update counter on button click
val settingIntent = HomeWidgetBackgroundIntent.getBroadcast(
context,
Uri.parse("myAppWidget://setting"),
)
setOnClickPendingIntent(R.id.setting_btn, settingIntent)
val rowFirst = HomeWidgetBackgroundIntent.getBroadcast(
context,
Uri.parse("myAppWidget://rowFirst"),
)
setOnClickPendingIntent(R.id.first_row, settingIntent)
val rowMiddle = HomeWidgetBackgroundIntent.getBroadcast(
context,
Uri.parse("myAppWidget://rowMiddle"),
)
setOnClickPendingIntent(R.id.middle_row, settingIntent)
val rowLast = HomeWidgetBackgroundIntent.getBroadcast(
context,
Uri.parse("myAppWidget://rowLast"),
)
setOnClickPendingIntent(R.id.last_row, settingIntent)
}
appWidgetManager.updateAppWidget(widgetId, views)
}
}
}

View File

@ -0,0 +1,43 @@
package com.didvan.didvanapp
import android.graphics.Bitmap
import android.graphics.BitmapShader
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.Shader
import com.squareup.picasso.Transformation
class RoundedTransformation(private val radius: Int, private val margin: Int) : Transformation {
override fun transform(source: Bitmap): Bitmap {
val paint = Paint()
paint.isAntiAlias = true
paint.setShader(
BitmapShader(
source, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP
)
)
val output = Bitmap.createBitmap(
source.getWidth(), source.getHeight(),
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(output)
canvas.drawRoundRect(
RectF(
margin.toFloat(), margin.toFloat(), (source.getWidth() - margin).toFloat(),
(
source.getHeight() - margin).toFloat()
), radius.toFloat(), radius.toFloat(), paint
)
if (source != output) {
source.recycle()
}
return output
}
override fun key(): String {
return "rounded(r=$radius, m=$margin)"
}
}

View File

@ -0,0 +1,21 @@
package com.didvan.didvanapp
import com.google.gson.annotations.SerializedName
data class WidgetResponse(
@SerializedName("id")
var id: Int = 0,
@SerializedName("title")
var title: String = "",
@SerializedName("createdAt")
var createdAt: String = "",
@SerializedName("type")
var type: String = "",
@SerializedName("link")
var link: String = "",
@SerializedName("category")
var category: String = "",
@SerializedName("image")
var image: String = "",
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for widgets to make the rounded corners based on the
appWidgetRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/appWidgetRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for views inside widgets to make the rounded corners based on the
appWidgetInnerRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/appWidgetInnerRadius" />
<solid android:color="?android:attr/colorAccent" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

View File

@ -0,0 +1,300 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:theme="@style/Theme.Android.AppWidgetContainer">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical"
android:id="@+id/root_lay"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:id="@+id/setting_btn"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentLeft="true"
android:src="@drawable/setting_logo" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_weight="1">
<ImageView
android:id="@+id/logo_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/logo" />
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginVertical="16dp"
android:background="#E0E0E0" />
<RelativeLayout
android:id="@+id/first_row"
android:layout_width="match_parent"
android:layout_height="78dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/first_image"
android:layout_width="74dp"
android:layout_height="74dp"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:src="@drawable/test" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:layout_toLeftOf="@id/first_image"
android:orientation="vertical"
>
<TextView
android:id="@+id/first_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="2"
android:text=" تحلیل شکاف فناوری صنعت فولاد ایران تحلیل شکاف فناوری صنعت فولاد ایران"
android:textColor="#012348"
android:textSize="13dp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2">
<TextView
android:id="@+id/first_duration"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="3"
android:gravity="center_vertical"
android:text="۳ دقیقه مطالعه"
android:textColor="#666666"
android:textSize="12dp" />
<RelativeLayout
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="8dp"
android:background="#E0E0E0" />
<TextView
android:id="@+id/first_tag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="4"
android:gravity="center_vertical"
android:text="رادار فناوری"
android:textColor="#292929"
android:textSize="12dp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/middle_row"
android:layout_width="match_parent"
android:layout_height="78dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/middle_image"
android:layout_width="74dp"
android:layout_height="74dp"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:src="@drawable/test" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:layout_toLeftOf="@id/middle_image"
android:orientation="vertical">
<TextView
android:id="@+id/middle_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="2"
android:text=" تحلیل شکاف فناوری صنعت فولاد ایران تحلیل شکاف فناوری صنعت فولاد ایران"
android:textColor="#012348"
android:textSize="13dp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2">
<TextView
android:id="@+id/middle_duration"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="3"
android:gravity="center_vertical"
android:text="۳ دقیقه مطالعه"
android:textColor="#666666"
android:textSize="12dp"
/>
<RelativeLayout
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="8dp"
android:background="#E0E0E0" />
<TextView
android:id="@+id/middle_tag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="4"
android:gravity="center_vertical"
android:text="رادار فناوری"
android:textColor="#292929"
android:textSize="12dp"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/last_row"
android:layout_width="match_parent"
android:layout_height="78dp"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/last_image"
android:layout_width="74dp"
android:layout_height="74dp"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:src="@drawable/test" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:layout_toLeftOf="@id/last_image"
android:orientation="vertical">
<TextView
android:id="@+id/last_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="2"
android:text=" تحلیل شکاف فناوری صنعت فولاد ایران تحلیل شکاف فناوری صنعت فولاد ایران"
android:textColor="#012348"
android:textSize="13dp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2"
>
<TextView
android:id="@+id/last_duration"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="3"
android:gravity="center_vertical"
android:text="۳ دقیقه مطالعه"
android:textColor="#666666"
android:textSize="12dp"
/>
<RelativeLayout
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="8dp"
android:background="#E0E0E0" />
<TextView
android:id="@+id/last_tag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_weight="4"
android:gravity="center_vertical"
android:text="رادار فناوری"
android:textColor="#292929"
android:textSize="12dp"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,14 @@
<resources>
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_background</item>
</style>
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_inner_view_background</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources>

View File

@ -0,0 +1,7 @@
<resources>
<declare-styleable name="AppWidgetAttrs">
<attr name="appWidgetPadding" format="dimension" />
<attr name="appWidgetInnerRadius" format="dimension" />
<attr name="appWidgetRadius" format="dimension" />
</declare-styleable>
</resources>

View File

@ -0,0 +1,6 @@
<resources>
<color name="light_blue_50">#FFE1F5FE</color>
<color name="light_blue_200">#FF81D4FA</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="widget_margin">0dp</dimen>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="appwidget_text">EXAMPLE</string>
<string name="add_widget">Add widget</string>
<string name="app_widget_description">This is an app widget description</string>
</resources>

View File

@ -15,4 +15,14 @@
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:background">?android:attr/colorBackground</item>
</style>
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
<item name="android:background">?android:attr/colorBackground</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources>

View File

@ -0,0 +1,17 @@
<resources>
<style name="Theme.Android.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
<!-- Radius of the outer bound of widgets to make the rounded corners -->
<item name="appWidgetRadius">16dp</item>
<!--
Radius of the inner view's bound of widgets to make the rounded corners.
It needs to be 8dp or less than the value of appWidgetRadius
-->
<item name="appWidgetInnerRadius">8dp</item>
</style>
<style name="Theme.Android.AppWidgetContainer" parent="Theme.Android.AppWidgetContainerParent">
<!-- Apply padding to avoid the content of the widget colliding with the rounded corners -->
<item name="appWidgetPadding">16dp</item>
</style>
</resources>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_widget_description"
android:initialKeyguardLayout="@layout/favourite_widget"
android:initialLayout="@layout/favourite_widget"
android:minWidth="250dp"
android:minHeight="180dp"
android:previewImage="@drawable/favwidg"
android:targetCellWidth="4"
android:targetCellHeight="3"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen" />

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,25 @@
import 'dart:developer';
import 'package:android_intent_plus/android_intent.dart';
import 'package:bot_toast/bot_toast.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/providers/media.dart';
import 'package:didvan/providers/theme.dart';
import 'package:didvan/providers/user.dart';
import 'package:didvan/routes/route_generator.dart';
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/notification/awsome/awsome_notification_handler.dart';
import 'package:didvan/services/notification/fcm/firebase_notification_handler.dart';
import 'package:didvan/views/podcasts/podcasts_state.dart';
import 'package:didvan/views/podcasts/studio_details/studio_details_state.dart';
import 'package:didvan/services/notification/lc/local_notification_service.dart';
import 'package:didvan/services/notification/lc/show_notification_handler.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:home_widget/home_widget.dart';
import 'package:provider/provider.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
@ -46,28 +46,98 @@ Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// LocalNotificationService.initialize();
// LocalNotificationService.display(message);
// LocalNotificationService.showBigPictureNotification();
AwsomeNotificationHandler().main();
AwsomeNotificationHandler().alarm();
AwsomeNotificationHandler().show(message);
print("Handling a background message: ${message.messageId}");
}
void main() async {
try {
WidgetsFlutterBinding.ensureInitialized();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
HomeWidget.registerBackgroundCallback(backgroundCallback);
// HomeWidget.registerInteractivityCallback(backgroundCallback);
HomeWidget.widgetClicked.listen((Uri? uri) {});
FirebaseNotificationHandler().initial();
} catch (e) {
print(e.toString());
}
runApp(const Didvan());
}
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
Future<void> backgroundCallback(Uri? uri) async {
AndroidIntent intent = const AndroidIntent(
action: 'android.intent.action.RUN',
package: 'com.didvan.didvanapp',
componentName: 'com.didvan.didvanapp.MainActivity',
);
class Didvan extends StatelessWidget {
await intent.launch();
switch (uri!.host) {
case 'setting':
HomeWidget.saveWidgetData("r", Routes.notificationStatusStep);
break;
case 'rowFirst':
HomeWidget.saveWidgetData("r", Routes.generalSettings);
break;
case 'rowMiddle':
HomeWidget.saveWidgetData("r", Routes.generalSettings);
break;
case 'rowLast':
HomeWidget.saveWidgetData("r", Routes.generalSettings);
break;
// Add more cases for other routes as needed
}
}
String r = "";
class Didvan extends StatefulWidget {
const Didvan({Key? key}) : super(key: key);
@override
State<Didvan> createState() => _DidvanState();
}
class _DidvanState extends State<Didvan> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance?.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance?.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
var v = context;
if (state == AppLifecycleState.resumed) {
await HomeWidget.getWidgetData<String>('r', defaultValue: "")
.then((value) {
if (value!.isNotEmpty) {
navigatorKey.currentState?.pushNamed(
value);
}
});
HomeWidget.saveWidgetData("r", "");
}
}
@override
Widget build(BuildContext context) {
return MultiProvider(
@ -111,7 +181,7 @@ class Didvan extends StatelessWidget {
builder: BotToastInit(),
//1. call BotToastInit
navigatorObservers: [BotToastNavigatorObserver()],
initialRoute: '/',
initialRoute: "/",
localizationsDelegates: const [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
@ -121,8 +191,7 @@ class Didvan extends StatelessWidget {
Locale("fa", "IR"),
],
locale: const Locale("fa", "IR"),
),
),
)),
),
),
);

View File

@ -56,6 +56,26 @@ import '../views/notification_time/notification_time.dart';
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case Routes.widgetSetting:
_createRoute(
const Splash(),
);
_createRoute(
const ProfilePage(),
);
_createRoute(
ChangeNotifierProvider<GeneralSettingsState>(
create: (context) => GeneralSettingsState(),
child: const GeneralSettings(),
),
);
return _createRoute(
ChangeNotifierProvider<CustomizeCategoryState>(
create: (context) => CustomizeCategoryState(),
child: FavoritesStep()),
);
case Routes.splash:
return _createRoute(
const Splash(),

View File

@ -28,4 +28,5 @@ class Routes {
static const String favouritesStep = '/favourites-step';
static const String notificationStatusStep = '/notification-status-step';
static const String notificationTime = '/notification-time';
static const String widgetSetting = '/widget-setting';
}

View File

@ -43,11 +43,11 @@ class RequestService {
}) {
if (body != null) _requestBody = body;
if (requestHeaders != null) _headers.addAll(requestHeaders);
if (useAutherization) _headers.addAll({'Authorization': 'Bearer $token'});
// _headers.addAll({
// 'Authorization':
// 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwicm9sZUlkIjo0LCJhcHBJZCI6MCwiaWF0IjoxNzEzOTM1NzkwfQ.i-SO9tLy0M9j-_C2Wh8tdp01vtYGlDZIBFPygglHQF0'
// });
// if (useAutherization) _headers.addAll({'Authorization': 'Bearer $token'});
_headers.addAll({
'Authorization':
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwicm9sZUlkIjo0LCJhcHBJZCI6MCwiaWF0IjoxNzEzOTM1NzkwfQ.i-SO9tLy0M9j-_C2Wh8tdp01vtYGlDZIBFPygglHQF0'
});
if (body != null) _requestBody = body;
}

View File

@ -197,6 +197,7 @@ class RequestHelper {
'$baseUrl/$type/$id/comments/add';
static String deleteComment(int id) => '$baseUrl/comment/$id/v2';
static String reportComment(int id) => '$baseUrl/comment/$id/report';
static String widgetNews() => '$baseUrl/user/widget';
static String _urlConcatGenerator(List<MapEntry<String, dynamic>> additions) {
String result = '';

View File

@ -1,13 +1,15 @@
import 'package:awesome_notifications/awesome_notifications.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../models/notification_message.dart';
import '../../network/request.dart';
import '../../network/request_helper.dart';
import 'awsome_notification_controller.dart';
class AwsomeNotificationHandler {
main() async {
alarm() async {
late ReceivedAction? initialAction;
AwesomeNotifications().initialize(
@ -83,6 +85,11 @@ class AwsomeNotificationHandler {
case "3":
await showNotificationTypeEmoji(notificationMessage);
break;
case "4":
await showNotificationScheduled(notificationMessage);
break;
}
}
@ -146,4 +153,49 @@ class AwsomeNotificationHandler {
'largeImage': 'path/to/largeImage.png', // Path to large image
}));
}
Future<DateTime> _getTime() async {
final service = RequestService(
RequestHelper.notificationTime(),
);
await service.httpGet();
if (service.isSuccess) {
final time = service.data('time');
DateFormat format = DateFormat("HH:mm");
DateTime dateTime = format.parse(time);
DateTime result = DateTime.now()
.copyWith(hour: dateTime.hour, minute: dateTime.minute);
return result;
} else {
return DateTime.now();
}
}
showNotificationScheduled(NotificationMessage message) async {
DateTime time = await _getTime();
AwesomeNotifications().createNotification(
content: NotificationContent(
id: DateTime.now().millisecondsSinceEpoch ~/ 1000,
channelKey: 'alerts',
title: 'Emojis are awes'
'ome too! ${Emojis.animals_lady_beetle}${Emojis.activites_balloon}${Emojis.emotion_red_heart}',
body:
'Simple body with a bunch of Emojis! ${Emojis.transport_police_car} ${Emojis.animals_dog} ${Emojis.flag_UnitedStates} ${Emojis.person_baby}',
largeIcon:
'https://cdn.britannica.com/72/232772-050-4E3D86CC/mind-blown-emoji-head-exploding-emoticon.jpg',
notificationLayout: NotificationLayout.BigPicture,
wakeUpScreen: true,
category: NotificationCategory.Alarm,
payload: {
'title': 'Notification Title',
'body': 'Notification Body',
'image': 'path/to/smallImage.png', // Path to small image
'largeImage': 'path/to/largeImage.png', // Path to large image
}),
schedule: NotificationCalendar(
hour: time.hour,
minute: time.minute,
// timezone: await AwesomeNotifications().getLocalTimeZoneIdentifier()
));
}
}

View File

@ -96,7 +96,7 @@ class FirebaseNotificationHandler {
// LocalNotificationService.initialize();
// LocalNotificationService.showBigPictureNotification();
// LocalNotificationService.display(message);
AwsomeNotificationHandler().main();
AwsomeNotificationHandler().alarm();
AwsomeNotificationHandler().show(message);
}
});

View File

@ -2,9 +2,12 @@ import 'package:didvan/config/design_config.dart';
import 'package:didvan/config/theme_data.dart';
import 'package:didvan/constants/app_icons.dart';
import 'package:didvan/models/view/action_sheet_data.dart';
import 'package:didvan/models/widget_response.dart';
import 'package:didvan/providers/theme.dart';
import 'package:didvan/routes/routes.dart';
import 'package:didvan/services/app_initalizer.dart';
import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart';
import 'package:didvan/utils/action_sheet.dart';
import 'package:didvan/views/home/bookmarks/bookmarks.dart';
import 'package:didvan/views/home/categories/categories_page.dart';
@ -17,6 +20,8 @@ import 'package:didvan/views/widgets/ink_wrapper.dart';
import 'package:didvan/views/widgets/logo_app_bar.dart';
import 'package:didvan/views/widgets/didvan/bnb.dart';
import 'package:flutter/material.dart';
import 'package:home_widget/home_widget.dart';
import 'package:persian_number_utility/persian_number_utility.dart';
import 'package:provider/provider.dart';
class Home extends StatefulWidget {
@ -26,7 +31,8 @@ class Home extends StatefulWidget {
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
class _HomeState extends State<Home>
with SingleTickerProviderStateMixin, WidgetsBindingObserver {
late final TabController _tabController;
@override
@ -50,9 +56,46 @@ class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
}
Future<void> _fetchWidget() async {
final service = RequestService(
RequestHelper.widgetNews(),
);
await service.httpGet();
List<WidgetResponse> responseList = [];
if (service.isSuccess) {
final favourites = service.data('content');
HomeWidget.saveWidgetData("token",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwicm9sZUlkIjo0LCJhcHBJZCI6MCwiaWF0IjoxNzEzOTM1NzkwfQ.i-SO9tLy0M9j-_C2Wh8tdp01vtYGlDZIBFPygglHQF0");
for (var i = 0; i < favourites.length; i++) {
HomeWidget.saveWidgetData(
"id${i + 1}", WidgetResponse.fromJson(favourites[i]).id.toString());
HomeWidget.saveWidgetData("title${i + 1}",
WidgetResponse.fromJson(favourites[i]).title.toString());
HomeWidget.saveWidgetData(
"createdAt${i + 1}",
DateTime.parse(
WidgetResponse.fromJson(favourites[i]).createdAt.toString())
.toPersianDateStr());
HomeWidget.saveWidgetData("type${i + 1}",
WidgetResponse.fromJson(favourites[i]).type.toString());
HomeWidget.saveWidgetData("link${i + 1}",
WidgetResponse.fromJson(favourites[i]).link.toString());
HomeWidget.saveWidgetData("category${i + 1}",
WidgetResponse.fromJson(favourites[i]).category.toString());
HomeWidget.saveWidgetData("image${i + 1}",
WidgetResponse.fromJson(favourites[i]).image.toString());
}
HomeWidget.updateWidget(
androidName: "FavWidget",
);
}
}
@override
Widget build(BuildContext context) {
_fetchWidget();
return Scaffold(
appBar: const LogoAppBar(),
body: Consumer<HomeState>(

View File

@ -89,6 +89,7 @@ class _SplashState extends State<Splash> {
Future<void> _initialize() async {
try {
var v = navigatorKey.currentContext;
ActionSheetUtils.context = navigatorKey.currentContext!;
if (kIsWeb) {
html.window.onBeforeUnload.listen((event) {

View File

@ -9,6 +9,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.33"
android_intent_plus:
dependency: "direct main"
description:
name: android_intent_plus
sha256: "2bfdbee8d65e7c26f88b66f0a91f2863da4d3596d8a658b4162c8de5cf04b074"
url: "https://pub.dev"
source: hosted
version: "5.0.2"
animated_custom_dropdown:
dependency: "direct main"
description:
@ -510,6 +518,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.23.8"
get:
dependency: "direct main"
description:
name: get
sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
url: "https://pub.dev"
source: hosted
version: "4.6.6"
graphs:
dependency: transitive
description:
@ -518,6 +534,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.1"
home_widget:
dependency: "direct main"
description:
name: home_widget
sha256: "29565bfee4b32eaf9e7e8b998d504618b779a74b2b1ac62dd4dac7468e66f1a3"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
html:
dependency: "direct main"
description:

View File

@ -81,6 +81,9 @@ dependencies:
flutter_local_notifications: ^17.1.2
awesome_notifications_core: ^0.9.0
awesome_notifications: any
home_widget: ^0.5.0
android_intent_plus: ^5.0.2
get: ^4.6.6
dev_dependencies:
flutter_test: