Skip to content
This repository has been archived by the owner on Aug 30, 2022. It is now read-only.

Notifications (Preview) #2

Draft
wants to merge 20 commits into
base: kohai
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Extensions-Lib
4 changes: 4 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ dependencies {

// Tap Target View for Tutorial
implementation 'uk.co.samuelwall:material-tap-target-prompt:3.1.1'

// work manager for notifications
implementation 'androidx.work:work-runtime:2.6.0-alpha02'
implementation 'androidx.concurrent:concurrent-futures:1.1.0'
}

// ~ Utility functions ~
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "cdf9447cf2d482f8a6abb2a12ff1e49c",
"entities": [
{
"tableName": "sent_notifications",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`identifier` TEXT NOT NULL, `expiration` INTEGER NOT NULL, PRIMARY KEY(`identifier`))",
"fields": [
{
"fieldPath": "notificationIdentifier",
"columnName": "identifier",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "expirationTimestamp",
"columnName": "expiration",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"identifier"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cdf9447cf2d482f8a6abb2a12ff1e49c')"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"formatVersion": 1,
"database": {
"version": 2,
"identityHash": "6ea776789be3023e82ca90a41cc45937",
"entities": [
{
"tableName": "sent_notifications",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`identifier` INTEGER NOT NULL, `description` TEXT NOT NULL, `expiration` INTEGER NOT NULL, PRIMARY KEY(`identifier`))",
"fields": [
{
"fieldPath": "notificationIdentifier",
"columnName": "identifier",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "expirationTimestamp",
"columnName": "expiration",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"identifier"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6ea776789be3023e82ca90a41cc45937')"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "cde411f7c5bcec3795d7ae88e871b4c8",
"entities": [
{
"tableName": "sent_notifications",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`identifier` INTEGER NOT NULL, `description` TEXT NOT NULL, `expiration` INTEGER NOT NULL, `is_scheduled` INTEGER NOT NULL, PRIMARY KEY(`identifier`))",
"fields": [
{
"fieldPath": "notificationIdentifier",
"columnName": "identifier",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "expirationTimestamp",
"columnName": "expiration",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isScheduledNotification",
"columnName": "is_scheduled",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"identifier"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cde411f7c5bcec3795d7ae88e871b4c8')"
]
}
}
70 changes: 44 additions & 26 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<queries>
<intent>
Expand All @@ -16,8 +17,8 @@
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/shared_app_label"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/TenshiTheme">
<activity
Expand All @@ -44,47 +45,64 @@
<category android:name="android.intent.category.BROWSABLE" />

<data
android:scheme="${redirect_scheme}"
android:host="${redirect_host}" />
android:host="${redirect_host}"
android:scheme="${redirect_scheme}" />
</intent-filter>
</activity>

<activity android:name=".ui.AnimeDetailsActivity"
android:parentActivityName=".ui.MainActivity"
android:label="@string/details_title"
android:hardwareAccelerated="true"
<activity
android:name=".ui.AnimeDetailsActivity"
android:configChanges="keyboard|orientation|screenSize"
android:hardwareAccelerated="true"
android:label="@string/details_title"
android:parentActivityName=".ui.MainActivity"
android:theme="@style/TenshiTheme.SplashScreen">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- TODO: mal http -->
<data
android:scheme="https"
android:host="myanimelist.net"
android:pathPrefix="/anime/"/>
android:pathPrefix="/anime/"
android:scheme="https" />
</intent-filter>
</activity>

<activity android:name=".ui.FullscreenImageActivity"
android:parentActivityName=".ui.AnimeDetailsActivity"
android:label="@string/fullscreen_img_title"
<activity
android:name=".ui.FullscreenImageActivity"
android:configChanges="keyboard|orientation|screenSize"
android:hardwareAccelerated="true"
android:configChanges="keyboard|orientation|screenSize"/>
android:label="@string/fullscreen_img_title"
android:parentActivityName=".ui.AnimeDetailsActivity" />

<activity android:name=".ui.SearchActivity"
android:parentActivityName=".ui.MainActivity"
android:label="@string/search_title"
android:hardwareAccelerated="true"
android:exported="true"
<activity
android:name=".ui.SearchActivity"
android:configChanges="keyboard|orientation|screenSize"
android:theme="@style/TenshiTheme.SplashScreen"/>

<activity android:name=".ui.settings.SettingsActivity"
android:exported="true"
android:hardwareAccelerated="true"
android:label="@string/search_title"
android:parentActivityName=".ui.MainActivity"
android:label="Settings"
android:theme="@style/TenshiTheme.SplashScreen" />

<activity
android:name=".ui.settings.SettingsActivity"
android:configChanges="keyboard|orientation|screenSize"
android:hardwareAccelerated="true"
android:configChanges="keyboard|orientation|screenSize"/>
android:label="Settings"
android:parentActivityName=".ui.MainActivity" />

<!-- notifications publisher -->
<receiver android:name=".notifications.NotificationPublisher" />

<!-- notifications boot listener -->
<receiver android:name=".notifications.boot.NotificationBootListener">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".notifications.boot.NotificationBootService" />

</application>
</manifest>
Binary file modified app/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 60 additions & 5 deletions app/src/main/java/io/github/shadow578/tenshi/TenshiApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
import io.github.shadow578.tenshi.mal.MalService;
import io.github.shadow578.tenshi.mal.Urls;
import io.github.shadow578.tenshi.mal.model.Token;
import io.github.shadow578.tenshi.notifications.TenshiNotificationChannel;
import io.github.shadow578.tenshi.notifications.TenshiNotificationManager;
import io.github.shadow578.tenshi.notifications.db.SentNotificationsDB;
import io.github.shadow578.tenshi.notifications.workers.NotificationWorkerHelper;
import io.github.shadow578.tenshi.ui.MainActivity;
import io.github.shadow578.tenshi.ui.SearchActivity;
import io.github.shadow578.tenshi.ui.oobe.OnboardingActivity;
Expand Down Expand Up @@ -95,6 +99,16 @@ public class TenshiApp extends Application {
*/
private TenshiDB database;

/**
* sent notifications database
*/
private SentNotificationsDB notifyDatabase;

/**
* notification manager
*/
private TenshiNotificationManager notificationManager;

@Override
public void onCreate() {
super.onCreate();
Expand All @@ -107,9 +121,20 @@ public void onCreate() {
TenshiPrefs.init(getApplicationContext());
tryAuthInit();

// init notifications api
notificationManager = new TenshiNotificationManager(getApplicationContext());

// right now, no further configuration is required.
// because of this, the configure function just accepts all channels
TenshiNotificationChannel.registerAll(getApplicationContext(), (value, channel) -> true);

// init database and start cleanup
database = TenshiDB.create(getApplicationContext());
cleanupDatabase();
cleanupAnimeDatabase();

// cleanup notification database
notifyDatabase = SentNotificationsDB.create(getApplicationContext());
cleanupNotifyDatabase();

// init and find content adapters
contentAdapterManager = new ContentAdapterManager(getApplicationContext(), new ContentAdapterManager.IPersistentStorageProvider() {
Expand All @@ -127,6 +152,9 @@ public void setPersistentStorage(@NonNull String uniqueName, int animeId, @NonNu
contentAdapterManager.discoverAndInit(false);
contentAdapterManager.addOnDiscoveryEndCallback(p
-> Log.i("Tenshi", fmt("Discovery finished with %d content adapters found", contentAdapterManager.getAdapterCount())));

// register workers
NotificationWorkerHelper.registerNotificationWorkers(getApplicationContext());
}

/**
Expand Down Expand Up @@ -173,12 +201,22 @@ private void initAppShortcuts() {
}

/**
* cleanup the database
* cleanup the anime database
*/
public void cleanupDatabase() {
public void cleanupAnimeDatabase() {
async(() -> {
final int removedEntities = database.cleanupDatabase();
Log.i("Tenshi", fmt("Database cleanup finished with %d entities removed", removedEntities));
Log.i("Tenshi", fmt("anime database cleanup finished with %d entities removed", removedEntities));
});
}

/**
* cleanup the notifications database
*/
private void cleanupNotifyDatabase() {
async(() -> {
final int removedEntries = notifyDatabase.notificationsDB().removeExpired();
Log.i("Tenshi", fmt("notification database cleanup finished with %d entries removed", removedEntries));
});
}

Expand Down Expand Up @@ -225,12 +263,13 @@ public void setTokenAndTryAuthInit(@Nullable Token t) {
createRetrofit();
}
}

/**
* invalidate and remove the saved auth token, saved user data and preferences, then redirect to the Login activity
*
* @param ctx the context to start the login activity from. has to be another activity, on which .finish() is called
*/
public void logoutAndLogin(@NonNull Activity ctx){
public void logoutAndLogin(@NonNull Activity ctx) {
// delete user data and config
deleteUserData();
TenshiPrefs.clear();
Expand Down Expand Up @@ -428,6 +467,22 @@ public static TenshiDB getDB() {
return INSTANCE.database;
}

/**
* @return the sent notifications database instance
*/
@NonNull
public static SentNotificationsDB getNotifyDB() {
return INSTANCE.notifyDatabase;
}

/**
* @return the notification manager
*/
@NonNull
public static TenshiNotificationManager getNotifyManager() {
return INSTANCE.notificationManager;
}

/**
* @return is a user authenticated and we have a access token?
*/
Expand Down
Loading