fixes, improvements. firebase
This commit is contained in:
@@ -151,7 +151,7 @@ namespace Darkmatter.Features.Artbook
|
||||
{
|
||||
if (!entry.HasValue || entry.Value.Thumbnail == null) return;
|
||||
var ct = _cts?.Token ?? CancellationToken.None;
|
||||
await _gallery.SaveImageAsync(entry.Value.Thumbnail, entry.Value.Id, ct);
|
||||
await _gallery.SaveImageAsync(entry.Value.Thumbnail, entry.Value.Name, ct);
|
||||
}
|
||||
|
||||
private void HandleLeftEditClicked() => OpenForEdit(GetLeftEntry());
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Darkmatter.Core.Contracts.Features.Capture;
|
||||
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
|
||||
using Darkmatter.Core.Contracts.Features.GameplayFlow;
|
||||
using Darkmatter.Core.Contracts.Features.Progression;
|
||||
using Darkmatter.Core.Contracts.Services.Capture;
|
||||
using Darkmatter.Core.Contracts.Services.Gallery;
|
||||
using Darkmatter.Core.Data.Signals.Features.Capture;
|
||||
@@ -18,19 +19,25 @@ namespace Darkmatter.Features.Capture
|
||||
private readonly IGameplaySceneRefs _refs;
|
||||
private readonly IEventBus _bus;
|
||||
private readonly CaptureConfig _config;
|
||||
private readonly IProgressionSystem _progression;
|
||||
private readonly IDrawingTemplateCatalog _catalog;
|
||||
|
||||
public CaptureSystem(
|
||||
ICaptureService captureService,
|
||||
IGalleryService galleryService,
|
||||
IGameplaySceneRefs refs,
|
||||
IEventBus bus,
|
||||
CaptureConfig config)
|
||||
CaptureConfig config,
|
||||
IProgressionSystem progression,
|
||||
IDrawingTemplateCatalog catalog)
|
||||
{
|
||||
_captureService = captureService;
|
||||
_galleryService = galleryService;
|
||||
_refs = refs;
|
||||
_bus = bus;
|
||||
_config = config;
|
||||
_progression = progression;
|
||||
_catalog = catalog;
|
||||
}
|
||||
|
||||
public async UniTask<byte[]> CapturePngAsync(bool saveToGallery = false, CancellationToken ct = default)
|
||||
@@ -44,9 +51,9 @@ namespace Darkmatter.Features.Capture
|
||||
{
|
||||
if (tex.LoadImage(png))
|
||||
{
|
||||
var fileName = await BuildFileNameAsync();
|
||||
_bus.Publish(new GallerySaveStartedSignal());
|
||||
await _galleryService.SaveImageAsync(tex,
|
||||
$"colorbook_{DateTime.UtcNow:yyyyMMdd_HHmmss}.png", ct);
|
||||
await _galleryService.SaveImageAsync(tex, fileName, ct);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
@@ -57,5 +64,20 @@ namespace Darkmatter.Features.Capture
|
||||
}
|
||||
return png;
|
||||
}
|
||||
|
||||
private async UniTask<string> BuildFileNameAsync()
|
||||
{
|
||||
var id = _progression.LastOpenedTemplateId;
|
||||
if (string.IsNullOrEmpty(id)) return null;
|
||||
try
|
||||
{
|
||||
var template = await _catalog.LoadAsync(id);
|
||||
return template?.DisplayName;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Darkmatter.Core;
|
||||
using Darkmatter.Core.Contracts.Features.DrawingCatalog;
|
||||
using Darkmatter.Core.Contracts.Features.Progression;
|
||||
using Darkmatter.Core.Data.Signals.Features.Drawing;
|
||||
using Darkmatter.Libs.Observer;
|
||||
using ZLinq;
|
||||
|
||||
namespace Darkmatter.Features.DrawingCatalog.Systems;
|
||||
|
||||
@@ -15,7 +12,6 @@ public sealed class DrawingCatalogController : IDrawingCatalogController
|
||||
{
|
||||
private readonly IDrawingTemplateCatalog _catalog;
|
||||
private readonly IEventBus _bus;
|
||||
private readonly IProgressionSystem _progression;
|
||||
|
||||
private readonly List<string> _visible = new();
|
||||
public IReadOnlyList<string> VisibleIds => _visible;
|
||||
@@ -23,11 +19,9 @@ public sealed class DrawingCatalogController : IDrawingCatalogController
|
||||
|
||||
public DrawingCatalogController(
|
||||
IDrawingTemplateCatalog catalog,
|
||||
IProgressionSystem progression,
|
||||
IEventBus bus)
|
||||
{
|
||||
_catalog = catalog;
|
||||
_progression = progression;
|
||||
_bus = bus;
|
||||
}
|
||||
|
||||
@@ -45,13 +39,8 @@ public sealed class DrawingCatalogController : IDrawingCatalogController
|
||||
private void Refresh()
|
||||
{
|
||||
_visible.Clear();
|
||||
var all = _catalog.AllTemplateIds;
|
||||
foreach (var id in all)
|
||||
if (!_progression.CompletedTemplateIds.AsValueEnumerable().Contains(id))
|
||||
_visible.Add(id);
|
||||
foreach (var id in all)
|
||||
if (_progression.CompletedTemplateIds.AsValueEnumerable().Contains(id))
|
||||
_visible.Add(id);
|
||||
_visible.AddRange(_catalog.AllTemplateIds);
|
||||
_visible.Sort(StringComparer.OrdinalIgnoreCase);
|
||||
ListChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Darkmatter.Libs.UnityUtils.Editor
|
||||
{
|
||||
public static class OpenEditorGalleryMenu
|
||||
{
|
||||
private const string MenuPath = "Tools/Colorbook/Open Editor Gallery";
|
||||
|
||||
[MenuItem(MenuPath)]
|
||||
private static void Open()
|
||||
{
|
||||
var dir = Path.Combine(Application.persistentDataPath, "Colorbook-Gallery");
|
||||
Directory.CreateDirectory(dir);
|
||||
EditorUtility.RevealInFinder(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55aad6d59cbf04999877c8c4b2f55836
|
||||
@@ -21,6 +21,8 @@ namespace Darkmatter.Services.Ads
|
||||
[SerializeField] private bool autoReload = true;
|
||||
[Tooltip("Seconds between auto-reload retries on failure.")]
|
||||
[SerializeField, Min(1f)] private float reloadDelaySeconds = 5f;
|
||||
[Tooltip("Max reload attempts before giving up.")]
|
||||
[SerializeField, Min(1)] private int reloadMaxAttempts = 6;
|
||||
|
||||
public bool IsInitialized => _initialized;
|
||||
public event Action<AdFormat, AdLoadState> LoadStateChanged;
|
||||
@@ -495,8 +497,14 @@ namespace Darkmatter.Services.Ads
|
||||
{
|
||||
try
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(reloadDelaySeconds), cancellationToken: cancellationToken);
|
||||
await LoadAsync(format, cancellationToken);
|
||||
for (int attempt = 0; attempt < reloadMaxAttempts; attempt++)
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromSeconds(reloadDelaySeconds), cancellationToken: cancellationToken);
|
||||
if (cancellationToken.IsCancellationRequested) return;
|
||||
if (IsReady(format)) return;
|
||||
if (await LoadAsync(format, cancellationToken)) return;
|
||||
}
|
||||
Debug.LogWarning($"[AdMobAdService] {format} reload gave up after {reloadMaxAttempts} attempts.");
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@ namespace Darkmatter.Services.Analytics
|
||||
{
|
||||
public void Register(IContainerBuilder builder)
|
||||
{
|
||||
#if FIREBASE_ANALYTICS_PRESENT
|
||||
builder.RegisterEntryPoint<FirebaseAnalyticsSystem>();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
#if FIREBASE_ANALYTICS
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Firebase.Crashlytics;
|
||||
@@ -10,7 +9,6 @@ namespace Darkmatter.Services.Analytics
|
||||
{
|
||||
public async UniTask StartAsync(CancellationToken cancellation = new CancellationToken())
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
await Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
|
||||
{
|
||||
var dependencyStatus = task.Result;
|
||||
@@ -39,8 +37,6 @@ namespace Darkmatter.Services.Analytics
|
||||
// Firebase Unity SDK is not safe to use here.
|
||||
}
|
||||
}, cancellation);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Darkmatter.Services.Gallery
|
||||
{
|
||||
[Serializable]
|
||||
public struct GalleryConfig
|
||||
{
|
||||
public Texture2D Background { get; }
|
||||
|
||||
public GalleryConfig(Texture2D background)
|
||||
{
|
||||
Background = background;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf2070de4e452444fa248a03c10928a6
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Darkmatter.Core.Contracts.Services.Gallery;
|
||||
@@ -8,36 +10,123 @@ namespace Darkmatter.Services.Gallery
|
||||
{
|
||||
public class GalleryService : IGalleryService
|
||||
{
|
||||
private readonly GalleryConfig _config;
|
||||
|
||||
public GalleryService(GalleryConfig config) => _config = config;
|
||||
|
||||
public async UniTask SaveImageAsync(Texture2D image, string fileName, CancellationToken cancellationToken)
|
||||
{
|
||||
var permission = await NativeGallery.RequestPermissionAsync(NativeGallery.PermissionType.Write,
|
||||
NativeGallery.MediaType.Image);
|
||||
|
||||
if (permission != NativeGallery.Permission.Granted)
|
||||
Texture2D composited = null;
|
||||
Texture2D toSave = image;
|
||||
if (_config.Background != null)
|
||||
{
|
||||
return;
|
||||
composited = CompositeOverBackground(image, _config.Background);
|
||||
toSave = composited;
|
||||
}
|
||||
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
var registration = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
|
||||
var resolvedName = BuildUniqueFileName(fileName);
|
||||
|
||||
NativeGallery.SaveImageToGallery(image, "Colorbook",
|
||||
filename: $"colorbook_{DateTime.UtcNow:yyyyMMdd_HHmmss}.png", callback: (success, path) =>
|
||||
try
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var bytes = toSave.EncodeToPNG();
|
||||
var dir = Path.Combine(Application.persistentDataPath, "Colorbook-Gallery");
|
||||
Directory.CreateDirectory(dir);
|
||||
var path = Path.Combine(dir, resolvedName);
|
||||
await File.WriteAllBytesAsync(path, bytes, cancellationToken);
|
||||
Debug.Log($"[GalleryService] (Editor) Image saved to: {path}");
|
||||
#else
|
||||
var permission = await NativeGallery.RequestPermissionAsync(NativeGallery.PermissionType.Write,
|
||||
NativeGallery.MediaType.Image);
|
||||
|
||||
if (permission != NativeGallery.Permission.Granted)
|
||||
{
|
||||
registration.Dispose();
|
||||
if (!success)
|
||||
{
|
||||
Debug.LogError("Failed to save image to gallery.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"Image saved to gallery at: {path}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tcs.TrySetResult();
|
||||
});
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
var registration = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
|
||||
|
||||
await tcs.Task;
|
||||
NativeGallery.SaveImageToGallery(toSave, "Colorbook",
|
||||
filename: resolvedName, callback: (success, path) =>
|
||||
{
|
||||
registration.Dispose();
|
||||
if (!success)
|
||||
{
|
||||
Debug.LogError("Failed to save image to gallery.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"Image saved to gallery at: {path}");
|
||||
}
|
||||
|
||||
tcs.TrySetResult();
|
||||
});
|
||||
|
||||
await tcs.Task;
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (composited != null) UnityEngine.Object.Destroy(composited);
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildUniqueFileName(string baseName)
|
||||
{
|
||||
var prefix = Sanitize(baseName);
|
||||
if (string.IsNullOrEmpty(prefix)) prefix = "drawing";
|
||||
return $"{prefix}_{DateTime.UtcNow:yyyyMMdd_HHmmssfff}.png";
|
||||
}
|
||||
|
||||
private static string Sanitize(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s)) return null;
|
||||
var name = Path.GetFileNameWithoutExtension(s).Trim();
|
||||
var sb = new StringBuilder(name.Length);
|
||||
foreach (var c in name)
|
||||
{
|
||||
if (char.IsLetterOrDigit(c)) sb.Append(c);
|
||||
else if (c == ' ' || c == '-' || c == '_') sb.Append('_');
|
||||
}
|
||||
return sb.Length == 0 ? null : sb.ToString();
|
||||
}
|
||||
|
||||
private static Texture2D CompositeOverBackground(Texture2D captured, Texture2D background)
|
||||
{
|
||||
int bgW = background.width;
|
||||
int bgH = background.height;
|
||||
int cW = captured.width;
|
||||
int cH = captured.height;
|
||||
|
||||
float fit = Mathf.Min(1f, Mathf.Min((float)bgW / cW, (float)bgH / cH));
|
||||
int finalW = Mathf.Max(1, Mathf.RoundToInt(cW * fit));
|
||||
int finalH = Mathf.Max(1, Mathf.RoundToInt(cH * fit));
|
||||
int offsetX = (bgW - finalW) / 2;
|
||||
int offsetY = (bgH - finalH) / 2;
|
||||
|
||||
var rt = RenderTexture.GetTemporary(bgW, bgH, 0, RenderTextureFormat.ARGB32);
|
||||
var prev = RenderTexture.active;
|
||||
try
|
||||
{
|
||||
Graphics.Blit(background, rt);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
GL.PushMatrix();
|
||||
GL.LoadPixelMatrix(0, bgW, bgH, 0);
|
||||
Graphics.DrawTexture(new Rect(offsetX, offsetY, finalW, finalH), captured);
|
||||
GL.PopMatrix();
|
||||
|
||||
var output = new Texture2D(bgW, bgH, TextureFormat.RGBA32, mipChain: false);
|
||||
output.ReadPixels(new Rect(0, 0, bgW, bgH), 0, 0);
|
||||
output.Apply();
|
||||
return output;
|
||||
}
|
||||
finally
|
||||
{
|
||||
RenderTexture.active = prev;
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,11 @@ namespace Darkmatter.Services.Gallery
|
||||
{
|
||||
public class GalleryModule : MonoBehaviour,IModule
|
||||
{
|
||||
[SerializeField] private Texture2D saveBackground;
|
||||
|
||||
public void Register(IContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterInstance(new GalleryConfig(saveBackground));
|
||||
builder.Register<IGalleryService,GalleryService>(Lifetime.Singleton);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user