Feat: Implémentation Notifications Périodiques via Service
- Ajout permission POST_NOTIFICATIONS et déclaration NotificationService dans Manifest. - Création NotificationHelper pour centraliser création canal et affichage notifications. - Création NotificationService utilisant Handler/postDelayed pour simuler l'envoi périodique de rappels (HighScore, Inactivité) - NOTE: WorkManager recommandé en prod. - Modification MainActivity: - Crée le canal via NotificationHelper. - Gère la demande de permission POST_NOTIFICATIONS (Android 13+) via ActivityResultLauncher, déclenchée par le switch dans les paramètres. - Démarre/Arrête NotificationService en fonction de l'état du switch Notifications. - Sauvegarde le timestamp de dernière partie jouée dans onPause. - Utilise NotificationHelper pour afficher la notification d'accomplissement (2048). - Suppression des méthodes/boutons de test de notification.
This commit is contained in:
parent
7dc7360e14
commit
bf914f291d
@ -32,6 +32,10 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<service
|
||||||
|
android:name=".NotificationService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -61,6 +61,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
private static final int BOARD_SIZE = 4;
|
private static final int BOARD_SIZE = 4;
|
||||||
private static final String NOTIFICATION_CHANNEL_ID = "BEST_2048_CHANNEL";
|
private static final String NOTIFICATION_CHANNEL_ID = "BEST_2048_CHANNEL";
|
||||||
private boolean notificationsEnabled = true;
|
private boolean notificationsEnabled = true;
|
||||||
|
private static final String LAST_PLAYED_TIME_KEY = "last_played_time";
|
||||||
|
|
||||||
// --- State Management ---
|
// --- State Management ---
|
||||||
private boolean statisticsVisible = false;
|
private boolean statisticsVisible = false;
|
||||||
@ -100,10 +101,14 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
EdgeToEdge.enable(this);
|
EdgeToEdge.enable(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
NotificationHelper.createNotificationChannel(this);
|
||||||
createNotificationChannel();
|
createNotificationChannel();
|
||||||
findViews();
|
findViews();
|
||||||
initializeGameAndStats();
|
initializeGameAndStats();
|
||||||
setupListeners();
|
setupListeners();
|
||||||
|
if (notificationsEnabled) {
|
||||||
|
startNotificationService();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -140,6 +145,13 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sauvegarde le timestamp actuel comme dernier moment joué. */
|
||||||
|
private void saveLastPlayedTime() {
|
||||||
|
if (preferences != null) {
|
||||||
|
preferences.edit().putLong(LAST_PLAYED_TIME_KEY, System.currentTimeMillis()).apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Initialisation ---
|
// --- Initialisation ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -692,12 +704,27 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
notificationManager.notify(notificationId, builder.build());
|
notificationManager.notify(notificationId, builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Affiche la notification d'accomplissement (ex: tuile 2048 atteinte). */
|
/** Démarre le NotificationService s'il n'est pas déjà lancé. */
|
||||||
|
private void startNotificationService() {
|
||||||
|
Intent serviceIntent = new Intent(this, NotificationService.class);
|
||||||
|
// Utiliser startForegroundService pour API 26+ si le service doit faire qqch rapidement
|
||||||
|
// mais pour une tâche périodique simple startService suffit.
|
||||||
|
startService(serviceIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arrête le NotificationService. */
|
||||||
|
private void stopNotificationService() {
|
||||||
|
Intent serviceIntent = new Intent(this, NotificationService.class);
|
||||||
|
stopService(serviceIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Affiche la notification d'accomplissement via le NotificationHelper. */
|
||||||
private void showAchievementNotification(int tileValue) {
|
private void showAchievementNotification(int tileValue) {
|
||||||
|
// Vérifie l'état global avant d'envoyer (au cas où désactivé entre-temps)
|
||||||
|
if (!notificationsEnabled) return;
|
||||||
String title = getString(R.string.notification_title_achievement);
|
String title = getString(R.string.notification_title_achievement);
|
||||||
String message = getString(R.string.notification_text_achievement, tileValue);
|
String message = getString(R.string.notification_text_achievement, tileValue);
|
||||||
// Utiliser un ID spécifique pour ce type de notif (ex: 1)
|
NotificationHelper.showNotification(this, title, message, 1); // ID 1 pour achievement
|
||||||
showNotification(this, title, message, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Affiche la notification de rappel du meilleur score (pour test). */
|
/** Affiche la notification de rappel du meilleur score (pour test). */
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
// Fichier NotificationHelper.java
|
||||||
|
package legion.muyue.best2048;
|
||||||
|
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
import androidx.core.content.ContextCompat; // Pour checkSelfPermission
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe utilitaire pour simplifier la création et l'affichage des notifications
|
||||||
|
* et la gestion du canal de notification pour l'application Best 2048.
|
||||||
|
*/
|
||||||
|
public class NotificationHelper {
|
||||||
|
|
||||||
|
/** Identifiant unique du canal de notification pour cette application. */
|
||||||
|
public static final String CHANNEL_ID = "BEST_2048_CHANNEL"; // Doit correspondre à celui utilisé avant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée le canal de notification requis pour Android 8.0 (API 26) et supérieur.
|
||||||
|
* Cette méthode est idempotente (l'appeler plusieurs fois n'a pas d'effet négatif).
|
||||||
|
* Doit être appelée avant d'afficher la première notification sur API 26+.
|
||||||
|
*
|
||||||
|
* @param context Contexte applicatif.
|
||||||
|
*/
|
||||||
|
public static void createNotificationChannel(Context context) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
CharSequence name = context.getString(R.string.notification_channel_name);
|
||||||
|
String description = context.getString(R.string.notification_channel_description);
|
||||||
|
int importance = NotificationManager.IMPORTANCE_DEFAULT; // Importance par défaut
|
||||||
|
|
||||||
|
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
|
||||||
|
channel.setDescription(description);
|
||||||
|
// Enregistre le canal auprès du système.
|
||||||
|
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||||
|
if (notificationManager != null) {
|
||||||
|
notificationManager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construit et affiche une notification.
|
||||||
|
* Vérifie la permission POST_NOTIFICATIONS sur Android 13+ avant d'essayer d'afficher.
|
||||||
|
*
|
||||||
|
* @param context Contexte (peut être une Activity ou un Service).
|
||||||
|
* @param title Titre de la notification.
|
||||||
|
* @param message Contenu texte de la notification.
|
||||||
|
* @param notificationId ID unique pour cette notification (permet de la mettre à jour ou l'annuler).
|
||||||
|
*/
|
||||||
|
public static void showNotification(Context context, String title, String message, int notificationId) {
|
||||||
|
// Vérification de la permission pour Android 13+
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.POST_NOTIFICATIONS) != android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||||
|
// Si la permission n'est pas accordée, ne pas tenter d'afficher la notification.
|
||||||
|
// L'application devrait idéalement gérer la demande de permission avant d'appeler cette méthode
|
||||||
|
// si elle sait que l'utilisateur a activé les notifications dans les paramètres.
|
||||||
|
System.err.println("Permission POST_NOTIFICATIONS manquante. Notification non affichée.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intent pour ouvrir MainActivity au clic
|
||||||
|
Intent intent = new Intent(context, MainActivity.class);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
|
int flags = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT;
|
||||||
|
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, flags);
|
||||||
|
|
||||||
|
// Construction de la notification via NotificationCompat pour la compatibilité
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
|
||||||
|
.setSmallIcon(R.drawable.ic_stat_notification_2048) // Votre icône de notification
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setContentText(message)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT) // Priorité normale
|
||||||
|
.setContentIntent(pendingIntent) // Action au clic
|
||||||
|
.setAutoCancel(true); // Ferme la notification après le clic
|
||||||
|
|
||||||
|
// Affichage de la notification
|
||||||
|
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
|
||||||
|
try {
|
||||||
|
notificationManager.notify(notificationId, builder.build());
|
||||||
|
} catch (SecurityException e){
|
||||||
|
// Gérer l'exception de sécurité qui peut survenir même avec la vérification ci-dessus dans certains cas limites
|
||||||
|
System.err.println("Erreur de sécurité lors de l'affichage de la notification : " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
app/src/main/java/legion/muyue/best2048/NotificationService.java
Normal file
135
app/src/main/java/legion/muyue/best2048/NotificationService.java
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// Fichier NotificationService.java
|
||||||
|
package legion.muyue.best2048;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper; // Important pour créer un Handler sur le Main Thread
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service exécuté en arrière-plan pour envoyer des notifications périodiques
|
||||||
|
* (rappel de meilleur score, rappel d'inactivité).
|
||||||
|
* Utilise un Handler pour planifier les tâches répétitives.
|
||||||
|
* NOTE : Pour une robustesse accrue (garantie d'exécution même si l'app est tuée),
|
||||||
|
* WorkManager serait préférable en production.
|
||||||
|
*/
|
||||||
|
public class NotificationService extends Service {
|
||||||
|
|
||||||
|
private static final int NOTIFICATION_ID_HIGHSCORE = 2; // Doit être différent des autres notifs
|
||||||
|
private static final int NOTIFICATION_ID_INACTIVITY = 3;
|
||||||
|
// Intervalles (exemples : 1 jour pour HS, 3 jours pour inactivité)
|
||||||
|
private static final long HIGHSCORE_INTERVAL_MS = TimeUnit.DAYS.toMillis(1);
|
||||||
|
private static final long INACTIVITY_INTERVAL_MS = TimeUnit.DAYS.toMillis(3);
|
||||||
|
private static final long CHECK_INTERVAL_MS = TimeUnit.HOURS.toMillis(6); // Intervalle de vérification plus fréquent
|
||||||
|
|
||||||
|
private Handler handler;
|
||||||
|
private Runnable periodicTaskRunnable;
|
||||||
|
|
||||||
|
// Clés SharedPreferences (doivent correspondre à celles utilisées ailleurs)
|
||||||
|
private static final String PREFS_NAME = "Best2048_Prefs";
|
||||||
|
private static final String HIGH_SCORE_KEY = "high_score";
|
||||||
|
private static final String LAST_PLAYED_TIME_KEY = "last_played_time"; // Nouvelle clé
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
// Utilise le Looper principal pour le Handler (simple, mais bloque si tâche longue)
|
||||||
|
// Pour des tâches plus lourdes, utiliser HandlerThread
|
||||||
|
handler = new Handler(Looper.getMainLooper());
|
||||||
|
// Pas besoin de créer le canal ici si MainActivity le fait déjà au démarrage
|
||||||
|
// NotificationHelper.createNotificationChannel(this);
|
||||||
|
|
||||||
|
periodicTaskRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Vérifie périodiquement s'il faut envoyer une notification
|
||||||
|
checkAndSendNotifications();
|
||||||
|
// Replanifie la tâche
|
||||||
|
handler.postDelayed(this, CHECK_INTERVAL_MS); // Vérifie toutes les X heures
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
// Lance la tâche périodique lors du démarrage du service
|
||||||
|
handler.removeCallbacks(periodicTaskRunnable); // Assure qu'il n'y a pas de doublon
|
||||||
|
handler.post(periodicTaskRunnable); // Lance immédiatement la première vérification
|
||||||
|
|
||||||
|
// START_STICKY : Le système essaiera de recréer le service s'il est tué.
|
||||||
|
return START_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
// Arrête la planification des tâches lorsque le service est détruit
|
||||||
|
if (handler != null && periodicTaskRunnable != null) {
|
||||||
|
handler.removeCallbacks(periodicTaskRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
// Service non lié (Started Service)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie les conditions et envoie les notifications périodiques si nécessaire.
|
||||||
|
*/
|
||||||
|
private void checkAndSendNotifications() {
|
||||||
|
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
|
||||||
|
boolean notificationsEnabled = prefs.getBoolean("notifications_enabled", true); // Vérifie si activé
|
||||||
|
|
||||||
|
if (!notificationsEnabled) {
|
||||||
|
// Si désactivé dans les prefs, on arrête potentiellement le service?
|
||||||
|
// Ou juste ne rien envoyer. Pour l'instant, ne rien envoyer.
|
||||||
|
// stopSelf(); // Arrêterait le service
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Notification High Score (Exemple: envoyer une fois par jour si non joué depuis ?) ---
|
||||||
|
// Logique simplifiée: on envoie juste le rappel basé sur un flag ou temps (pas implémenté ici)
|
||||||
|
// Pour une vraie app, il faudrait une logique pour ne pas spammer.
|
||||||
|
// Exemple: Envoyer si le dernier envoi date de plus de HIGHSCORE_INTERVAL_MS ?
|
||||||
|
int highScore = prefs.getInt(HIGH_SCORE_KEY, 0);
|
||||||
|
// Temporairement on l'envoie à chaque check pour test (à modifier!)
|
||||||
|
// if (shouldSendHighScoreNotification()) {
|
||||||
|
showHighScoreNotificationNow(highScore);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// --- Notification d'Inactivité ---
|
||||||
|
long lastPlayedTime = prefs.getLong(LAST_PLAYED_TIME_KEY, 0);
|
||||||
|
if (lastPlayedTime > 0 && (System.currentTimeMillis() - lastPlayedTime > INACTIVITY_INTERVAL_MS)) {
|
||||||
|
// Si l'inactivité dépasse le seuil
|
||||||
|
showInactivityNotificationNow();
|
||||||
|
// Optionnel: Mettre à jour lastPlayedTime pour ne pas renvoyer immédiatement ?
|
||||||
|
// Ou attendre que l'utilisateur rejoue pour mettre à jour lastPlayedTime dans onPause.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Affiche la notification High Score */
|
||||||
|
private void showHighScoreNotificationNow(int highScore) {
|
||||||
|
String title = getString(R.string.notification_title_highscore);
|
||||||
|
String message = getString(R.string.notification_text_highscore, highScore);
|
||||||
|
NotificationHelper.showNotification(this, title, message, NOTIFICATION_ID_HIGHSCORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Affiche la notification d'Inactivité */
|
||||||
|
private void showInactivityNotificationNow() {
|
||||||
|
String title = getString(R.string.notification_title_inactivity);
|
||||||
|
String message = getString(R.string.notification_text_inactivity);
|
||||||
|
NotificationHelper.showNotification(this, title, message, NOTIFICATION_ID_INACTIVITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajouter ici une logique plus fine si nécessaire pour savoir QUAND envoyer les notifs périodiques
|
||||||
|
// private boolean shouldSendHighScoreNotification() { ... }
|
||||||
|
|
||||||
|
}
|
@ -1,170 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<path
|
|
||||||
android:fillColor="#3DDC84"
|
|
||||||
android:pathData="M0,0h108v108h-108z" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M9,0L9,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,0L19,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,0L29,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,0L39,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,0L49,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,0L59,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,0L69,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,0L79,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M89,0L89,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M99,0L99,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,9L108,9"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,19L108,19"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,29L108,29"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,39L108,39"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,49L108,49"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,59L108,59"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,69L108,69"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,79L108,79"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,89L108,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,99L108,99"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,29L89,29"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,39L89,39"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,49L89,49"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,59L89,59"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,69L89,69"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,79L89,79"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,19L29,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,19L39,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,19L49,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,19L59,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,19L69,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,19L79,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
</vector>
|
|
@ -1,30 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:endX="85.84757"
|
|
||||||
android:endY="92.4963"
|
|
||||||
android:startX="42.9492"
|
|
||||||
android:startY="49.59793"
|
|
||||||
android:type="linear">
|
|
||||||
<item
|
|
||||||
android:color="#44000000"
|
|
||||||
android:offset="0.0" />
|
|
||||||
<item
|
|
||||||
android:color="#00000000"
|
|
||||||
android:offset="1.0" />
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFF"
|
|
||||||
android:fillType="nonZero"
|
|
||||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
|
||||||
android:strokeWidth="1"
|
|
||||||
android:strokeColor="#00000000" />
|
|
||||||
</vector>
|
|
BIN
app/src/main/res/drawable/logo.jpeg
Normal file
BIN
app/src/main/res/drawable/logo.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
BIN
app/src/main/res/drawable/logolegionmuyue.png~
Normal file
BIN
app/src/main/res/drawable/logolegionmuyue.png~
Normal file
Binary file not shown.
After Width: | Height: | Size: 427 KiB |
@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@drawable/ic_launcher_background" />
|
<foreground android:drawable="@drawable/logo" />
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
<monochrome android:drawable="@drawable/logo" />
|
||||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@drawable/ic_launcher_background" />
|
<foreground android:drawable="@drawable/logo" />
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
<monochrome android:drawable="@drawable/logo" />
|
||||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
Loading…
x
Reference in New Issue
Block a user