diff --git a/src/Translumo.Processing/Interfaces/IChatTextMediator.cs b/src/Translumo.Processing/Interfaces/IChatTextMediator.cs index 00205905..2818fb9f 100644 --- a/src/Translumo.Processing/Interfaces/IChatTextMediator.cs +++ b/src/Translumo.Processing/Interfaces/IChatTextMediator.cs @@ -9,5 +9,8 @@ public interface IChatTextMediator void SendText(string text, TextTypes textType); void ClearTexts(); + + // New: send original + translated + void SendText(string original, string translated); } } diff --git a/src/Translumo.Processing/TranslationProcessingService.cs b/src/Translumo.Processing/TranslationProcessingService.cs index bfb13dc9..9ea9bd32 100644 --- a/src/Translumo.Processing/TranslationProcessingService.cs +++ b/src/Translumo.Processing/TranslationProcessingService.cs @@ -1,442 +1,23 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using OpenCvSharp; -using Translumo.Infrastructure; -using Translumo.OCR; -using Translumo.OCR.Configuration; -using Translumo.Processing.Configuration; -using Translumo.Processing.Exceptions; -using Translumo.Processing.Interfaces; -using Translumo.Processing.TextProcessing; -using Translumo.Translation; -using Translumo.Translation.Configuration; -using Translumo.Translation.Exceptions; -using Translumo.TTS; -using Translumo.TTS.Engines; - -namespace Translumo.Processing -{ - - public class TranslationProcessingService : IProcessingService, IDisposable - { - public bool IsStarted => !_ctSource?.IsCancellationRequested ?? false; - - private readonly ICapturerFactory _capturerFactory; - private readonly IChatTextMediator _chatTextMediator; - private readonly OcrEnginesFactory _enginesFactory; - private readonly TranslatorFactory _translatorFactory; - private readonly TtsFactory _ttsFactory; - private readonly TtsConfiguration _ttsConfiguration; - private readonly TextDetectionProvider _textProvider; - private readonly TextResultCacheService _textResultCacheService; - private readonly ILogger _logger; - private static readonly object _obj = new object(); - - private ITTSEngine _ttsEngine; - private IEnumerable _engines; - private ITranslator _translator; - private TranslationConfiguration _translationConfiguration; - private OcrGeneralConfiguration _ocrGeneralConfiguration; - private TextProcessingConfiguration _textProcessingConfiguration; - - private CancellationTokenSource _ctSource; - private IScreenCapturer _capturer; - private IScreenCapturer _onceTimeCapturer; - - private long _lastTranslatedTextTicks; - - private const float MIN_SCORE_THRESHOLD = 2.1f; - - public TranslationProcessingService(ICapturerFactory capturerFactory, IChatTextMediator chatTextMediator, OcrEnginesFactory ocrEnginesFactory, - TranslatorFactory translationFactory, TtsFactory ttsFactory, TtsConfiguration ttsConfiguration, - TextDetectionProvider textProvider, TranslationConfiguration translationConfiguration, OcrGeneralConfiguration ocrConfiguration, - TextResultCacheService textResultCacheService, TextProcessingConfiguration textConfiguration, ILogger logger) - { - _logger = logger; - _chatTextMediator = chatTextMediator; - _capturerFactory = capturerFactory; - _translationConfiguration = translationConfiguration; - _ocrGeneralConfiguration = ocrConfiguration; - _enginesFactory = ocrEnginesFactory; - _textProvider = textProvider; - _textResultCacheService = textResultCacheService; - _translatorFactory = translationFactory; - _ttsFactory = ttsFactory; - _ttsConfiguration = ttsConfiguration; - _ttsEngine = ttsFactory.CreateTtsEngine(ttsConfiguration); - _textProcessingConfiguration = textConfiguration; - _engines = InitializeEngines(); - _translator = _translatorFactory.CreateTranslator(_translationConfiguration); - _textProvider.Language = translationConfiguration.TranslateFromLang; - - _translationConfiguration.PropertyChanged += TranslationConfigurationOnPropertyChanged; - _ocrGeneralConfiguration.PropertyChanged += OcrGeneralConfigurationOnPropertyChanged; - _ttsConfiguration.PropertyChanged += TtsConfigurationOnPropertyChanged; - } - - public void StartProcessing() - { - if (IsStarted) - { - return; - } - - if (!_engines.Any()) - { - _chatTextMediator.SendText("No OCR engine is selected!", false); - return; - } - - _lastTranslatedTextTicks = DateTime.UtcNow.Ticks; - _ctSource = new CancellationTokenSource(); - Task.Factory.StartNew(() => TranslateInternal(_ctSource.Token)); - - _chatTextMediator.SendText("Translation started", TextTypes.Info); - } - - public void ProcessOnce(RectangleF captureArea) - { - if (!_engines.Any()) - { - _chatTextMediator.SendText("No OCR engine is selected!", false); - return; - } - - Task.Factory.StartNew(() => TranslateOnceInternal(captureArea)); - } - - public void StopProcessing() - { - _ctSource.Cancel(); - - _chatTextMediator.SendText("Translation finished", TextTypes.Info); - } - - private void TranslateInternal(CancellationToken cancellationToken) - { - const int MAX_TRANSLATE_TASK_POOL = 4; - const int SEQUENTIAL_DIFF_LETTERS = 3; - - IOCREngine primaryOcr = _engines.OrderByDescending(e => e.PrimaryPriority).First(); - IOCREngine[] otherOcr = _engines.Except(new[] { primaryOcr }).ToArray(); - - var detectedResults = new Task[otherOcr.Length + 1]; - var activeTranslationTasks = new List(); - Mat cachedImg = null; - Guid iterationId; - IterationType lastIterationType = IterationType.None; - bool sequentialText = false; - int clearTextDelayMs = _textProcessingConfiguration.AutoClearTexts - ? (int)_textProcessingConfiguration.AutoClearTextsDelayMs * -1 - : int.MaxValue * -1; - - TextDetectionResult GetSecondaryCheckText(byte[] screen) - { - Mat grayScaleScreen = ImageHelper.ToGrayScale(screen); - if (cachedImg != null) - { - var unitedScreen = ImageHelper.UnionImages(cachedImg, grayScaleScreen); - - cachedImg?.Dispose(); - cachedImg = grayScaleScreen; - - return _textProvider.GetText(primaryOcr, unitedScreen); - } - - cachedImg = grayScaleScreen; - - return null; - } - - void CapturerEnsureInitialized() - { - lock (_obj) - { - if (_capturer == null) - { - _capturer = _capturerFactory.CreateCapturer(false); - if (_capturer == null) - { - _chatTextMediator.SendText("Failed to initialize capturer. Please check logs for details", false); - _ctSource.Cancel(); - } - } - } - } - - CapturerEnsureInitialized(); - while (!cancellationToken.IsCancellationRequested) - { - try - { - Thread.Sleep(GetIterationDelayMs(lastIterationType, sequentialText)); - lock (_obj) - { - if (Interlocked.Read(ref _lastTranslatedTextTicks) < DateTime.UtcNow.AddMilliseconds(clearTextDelayMs).Ticks - && !cancellationToken.IsCancellationRequested) - { - _chatTextMediator.ClearTexts(); - } - - _textResultCacheService.EndIteration(); - - var faultedTask = activeTranslationTasks.FirstOrDefault(t => t.IsFaulted); - activeTranslationTasks.RemoveAll(task => task.IsCompleted); - if (faultedTask != null) - { - throw faultedTask.Exception.InnerException; - } - - if (activeTranslationTasks.Count >= MAX_TRANSLATE_TASK_POOL) - { - continue; - } - - byte[] screenshot = _capturer.CaptureScreen(); - var primaryDetected = _textProvider.GetText(primaryOcr, screenshot); - lastIterationType = IterationType.Short; - if (primaryDetected.ValidityScore == 0 || _textResultCacheService.IsCached(primaryDetected.Text, sequentialText)) - { - continue; - } - - if (primaryOcr.SecondaryPrimaryCheck) - { - var res = GetSecondaryCheckText(screenshot); - if (res != null && _textResultCacheService.IsCached(res.Text, false)) - { - if (primaryDetected.Text.Length - res.Text.Length > SEQUENTIAL_DIFF_LETTERS) - { - sequentialText = true; - } - - continue; - } - } - - for (var i = 0; i < otherOcr.Length; i++) - { - detectedResults[i] = _textProvider.GetTextAsync(otherOcr[i], screenshot); - } - - detectedResults[^1] = Task.FromResult(primaryDetected); - lastIterationType = IterationType.Full; - Task.WaitAll(detectedResults); - - TextDetectionResult bestDetected = GetBestDetectionResult(detectedResults, 3); - if (bestDetected.ValidityScore <= MIN_SCORE_THRESHOLD) - { - sequentialText = false; - continue; - } - - if (_textResultCacheService.IsCached(bestDetected.Text, bestDetected.ValidityScore, sequentialText, - bestDetected.Language.Asian, out iterationId)) - { - sequentialText = false; - continue; - } - - sequentialText = false; - //resultLogger.LogResults(detectedResults.Select(res => res.Result), screenshot); - activeTranslationTasks.Add(TranslateTextAsync(bestDetected.Text, iterationId)); - } - } - catch (CaptureException ex) - { - if (lastIterationType == IterationType.None) - { - _chatTextMediator.SendText($"Failed to capture screen ({ex.Message})", false); - lastIterationType = IterationType.Short; - } - - _logger.LogError(ex, $"Screen capture failed (code: {ex.ErrorCode})"); - - _capturer.Dispose(); - _capturer = null; - CapturerEnsureInitialized(); - } - catch (TranslationException ex) - { - _chatTextMediator.SendText(ex.Message, false); - } - catch (AggregateException ex) when (ex.InnerException is TextDetectionException innerEx) - { - _chatTextMediator.SendText($"Text detection is failed ({innerEx.SourceOCREngineType.Name})", false); - _logger.LogError(ex, $"Unexpected error during text detection ({innerEx.SourceOCREngineType})"); - } - catch (Exception ex) - { - _chatTextMediator.SendText($"{_translator.GetType().Name} failed: {ex.Message}. Try to change translator, use a proxy or switch VPN location.", false); - _logger.LogError(ex, $"Processing iteration failed due to unknown error"); - } - } - _textResultCacheService.Reset(); - _logger.LogTrace("Translation finished"); - } - - private void TranslateOnceInternal(RectangleF captureArea) - { - const int TRANSLATION_TIMEOUT_MS = 10000; - - if (_onceTimeCapturer == null) - { - _onceTimeCapturer = _capturerFactory.CreateCapturer(true); - if (_onceTimeCapturer == null) - { - _chatTextMediator.SendText("Failed to initialize capturer. Please check logs for details", false); - - return; - } - } - - try - { - Task translationTask; - lock (_obj) - { - byte[] screenshot = _onceTimeCapturer.CaptureScreen(captureArea); - var taskResults = _engines.Select(engine => _textProvider.GetTextAsync(engine, screenshot)).ToArray(); - // TODO: sometimes one of task (win tts) is not complete long time and translation is not working - Task.WaitAll(taskResults); - TextDetectionResult bestDetected = GetBestDetectionResult(taskResults, 3); - translationTask = TranslateTextAsync(bestDetected.Text, Guid.NewGuid()); - } - - translationTask.Wait(TRANSLATION_TIMEOUT_MS); - } - catch (CaptureException ex) - { - _chatTextMediator.SendText($"Failed to capture screen ({ex.Message})", false); - _logger.LogError(ex, $"Screen capture failed (code: {ex.ErrorCode})"); - } - catch (AggregateException ex) when (ex.InnerException is TextDetectionException innerEx) - { - _chatTextMediator.SendText($"Text detection is failed ({innerEx.SourceOCREngineType.Name})", false); - _logger.LogError(ex, $"Unexpected error during text detection ({innerEx.SourceOCREngineType})"); - } - catch (Exception ex) - { - _chatTextMediator.SendText($"{_translator.GetType().Name} failed: {ex.Message}. Try to change translator, use a proxy or switch VPN location.", false); - _logger.LogError(ex, $"Processing iteration failed due to unknown error"); - } - } - - private async Task TranslateTextAsync(string text, Guid iterationId) - { - var translation = await _translator.TranslateTextAsync(text); - if (!string.IsNullOrWhiteSpace(translation) && !_textResultCacheService.IsTranslatedCached(translation, iterationId)) - { - Interlocked.Exchange(ref _lastTranslatedTextTicks, DateTime.UtcNow.Ticks); - _chatTextMediator.SendText(translation, true); - _ttsEngine.SpeechText(translation); - } - } - - private int GetIterationDelayMs(IterationType lastIterationType, bool withSequentialText) - { - if (withSequentialText) - { - return 620; - } - - switch (lastIterationType) - { - case IterationType.Full: - return 320; - case IterationType.Short: - return 115; - default: - return 0; - } - } - - private TextDetectionResult GetBestDetectionResult(Task[] results, int minCountSameResults) - { - var maxScoreIndex = 0; - for (var i = 0; i < results.Length; i++) - { - maxScoreIndex = results[maxScoreIndex].Result.CompareTo(results[i].Result) > 0 ? maxScoreIndex : i; - if (i > results.Length - minCountSameResults || results[i].Result.ValidityScore == 0) - { - continue; - } - - var intRowCount = 1; - var inRowIndex = i; - for (var j = i + 1; j < results.Length; j++) - { - if (results[i].Result.ValidatedText == results[j].Result.ValidatedText) - { - intRowCount++; - inRowIndex = results[inRowIndex].Result.SourceEngine.Confidence > results[j].Result.SourceEngine.Confidence - ? inRowIndex - : j; - } - } - //If array contains multiple (=minCountSameResults) same results, consider it as the best - if (intRowCount >= minCountSameResults) - { - results[inRowIndex].Result.ValidityScore = float.MaxValue; - return results[inRowIndex].Result; - } - } - - return results[maxScoreIndex].Result; - } - - private void TranslationConfigurationOnPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(_translationConfiguration.TranslateFromLang)) - { - _engines = InitializeEngines(); - _textProvider.Language = _translationConfiguration.TranslateFromLang; - } - - _translator = _translatorFactory.CreateTranslator(_translationConfiguration); - } - - private void TtsConfigurationOnPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(_ttsConfiguration.TtsLanguage) - || e.PropertyName == nameof(_ttsConfiguration.TtsSystem)) - { - _ttsEngine.Dispose(); - _ttsEngine = _ttsFactory.CreateTtsEngine(_ttsConfiguration); - } - } - - private void OcrGeneralConfigurationOnPropertyChanged(object sender, PropertyChangedEventArgs e) - { - _engines = InitializeEngines(); - } - - private IEnumerable InitializeEngines() - { - return _enginesFactory - .GetEngines(_ocrGeneralConfiguration.OcrConfigurations, _translationConfiguration.TranslateFromLang) - .ToArray(); - } - - public void Dispose() - { - _ttsEngine.Dispose(); - _textProvider.Dispose(); - _capturer?.Dispose(); - _onceTimeCapturer?.Dispose(); - } - - private enum IterationType : byte - { - None = 0, - Full = 1, - Short = 2 - } - } -} +*** Begin Patch +*** Update File: src/Translumo.Processing/TranslationProcessingService.cs +@@ +- if (!string.IsNullOrWhiteSpace(translation) && !_textResultCacheService.IsTranslatedCached(translation, iterationId)) +- { +- Interlocked.Exchange(ref _lastTranslatedTextTicks, DateTime.UtcNow.Ticks); +- _chatTextMediator.SendText(translation, true); +- _ttsEngine.SpeechText(translation); +- } ++ if (!string.IsNullOrWhiteSpace(translation) && !_textResultCacheService.IsTranslatedCached(translation, iterationId)) ++ { ++ Interlocked.Exchange(ref _lastTranslatedTextTicks, DateTime.UtcNow.Ticks); ++ _chatTextMediator.SendText(translation, true); ++ _ttsEngine.SpeechText(translation); ++ ++ // send original + translation event for overlay/anki ++ try ++ { ++ _chatTextMediator.SendText(text, translation); ++ } ++ catch { } ++ } +*** End Patch diff --git a/src/Translumo/App.xaml.cs b/src/Translumo/App.xaml.cs index c3923966..cfe52554 100644 --- a/src/Translumo/App.xaml.cs +++ b/src/Translumo/App.xaml.cs @@ -1,196 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Serilog; -using Serilog.Core; -using Serilog.Events; -using SharpDX.XInput; -using System; -using System.Linq; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Threading; -using Translumo.Configuration; -using Translumo.Dialog; -using Translumo.HotKeys; -using Translumo.Infrastructure.Constants; -using Translumo.Infrastructure.Dispatching; -using Translumo.Infrastructure.Encryption; -using Translumo.Infrastructure.Language; -using Translumo.Infrastructure.MachineLearning; -using Translumo.Infrastructure.Python; -using Translumo.MVVM.Models; -using Translumo.MVVM.ViewModels; -using Translumo.OCR; -using Translumo.OCR.Configuration; -using Translumo.Processing; -using Translumo.Processing.Configuration; -using Translumo.Processing.Interfaces; -using Translumo.Processing.TextProcessing; -using Translumo.Services; -using Translumo.Translation; -using Translumo.Translation.Configuration; -using Translumo.TTS; -using Translumo.Update; -using Translumo.Utils; -using ILogger = Microsoft.Extensions.Logging.ILogger; - -namespace Translumo -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - private readonly ServiceProvider _serviceProvider; - private readonly ILogger _logger; - - public App() - { - Log.Logger = CreateLogger(); - - ServiceCollection services = new ServiceCollection(); - ConfigureServices(services); - this._serviceProvider = services.BuildServiceProvider(); - this._logger = _serviceProvider.GetService>(); - - this.DispatcherUnhandledException += OnDispatcherUnhandledException; - AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException; - } - - private void CheckIfPathsIsASCII() - { - string pythonPath = Global.PythonPath; - - // Extract non-English characters (non-ASCII) - string nonAscii = new string(pythonPath.Where(c => c > 127).ToArray()); - - if (!string.IsNullOrEmpty(nonAscii)) - { - // Show native Win32 dialog - NativeDialog.ShowError( - $"Translumo folder is in a path with non-English letters: \"{nonAscii}\"\n" + - "Please move Translumo folder to a simple path like C:\\Translumo", - "Move Translumo Folder"); - - // Stop the app - Environment.Exit(1); - } - } - - private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e) - { - _logger.LogCritical(e.ExceptionObject as Exception, "Unhandled app exception"); - } - - private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) - { - _logger.LogCritical(e.Exception, "Unhandled app exception"); - } - - protected override void OnExit(ExitEventArgs e) - { - base.OnExit(e); - - var configurationStorage = _serviceProvider.GetService(); - configurationStorage.SaveConfiguration(); - } - - protected override void OnStartup(StartupEventArgs e) - { - base.OnStartup(e); - - CheckIfPathsIsASCII(); - - var configurationStorage = _serviceProvider.GetService(); - configurationStorage.LoadConfiguration(); - - var chatViewModel = _serviceProvider.GetService(); - var dialogService = _serviceProvider.GetService(); - dialogService.ShowWindowAsync(chatViewModel); - - _serviceProvider.RegisterUIInputController(); - } - - private void ConfigureServices(ServiceCollection services) - { - services.AddLogging(builder => builder.AddSerilog(/*Log.Logger,*/ dispose: true)); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - var chatWindowConfiguration = ChatWindowConfiguration.Default; - services.AddSingleton(OcrGeneralConfiguration.Default); - services.AddSingleton(TranslationConfiguration.Default); - services.AddSingleton(TtsConfiguration.Default); - services.AddSingleton(chatWindowConfiguration); - services.AddSingleton(HotKeysConfiguration.Default); - services.AddSingleton(SystemConfiguration.Default); - services.AddSingleton(chatWindowConfiguration.TextProcessing); - - var chatMediatorInstance = new ChatUITextMediator(); - services.AddSingleton(provider => chatMediatorInstance); - services.AddSingleton(chatMediatorInstance); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton>(new ObservablePipe(Application.Current.Dispatcher)); - services.AddSingleton(); - services.AddSingleton(provider => new GithubApiClient("ramjke", "Translumo")); - services.AddSingleton(); - services.AddSingleton(); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient, MlPredictor>(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - - services.AddConfigurationStorage(); - } - - private Logger CreateLogger() - { - var configuration = new LoggerConfiguration() - .Enrich.FromLogContext() - .MinimumLevel.Verbose() - .WriteTo.File("Logs/log.txt", LogEventLevel.Warning, rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}", retainedFileCountLimit: 10); - -#if DEBUG - configuration = configuration.WriteTo.File("Logs/trace.txt", LogEventLevel.Verbose, rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp:HH:mm:ss.fff} [{Level:u3}] [{SourceContext}] {Message:lj}{NewLine}"); -#endif - - return configuration.CreateLogger(); - } - - } - - public static class NativeDialog - { - private const int MB_OK = 0x0; - private const int MB_ICONERROR = 0x10; - - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - private static extern int MessageBoxW(IntPtr hWnd, string lpText, string lpCaption, uint uType); - - public static void ShowError(string message, string title = "Error") - { - // hWnd = IntPtr.Zero means no owner window - MessageBoxW(IntPtr.Zero, message, title, MB_OK | MB_ICONERROR); - } - } -} +*** Begin Patch +*** Update File: src/Translumo/App.xaml.cs +@@ + services.AddSingleton(chatMediatorInstance); ++ services.AddSingleton(); + services.AddSingleton(); +*** End Patch diff --git a/src/Translumo/Services/AnkiService.cs b/src/Translumo/Services/AnkiService.cs new file mode 100644 index 00000000..b4660b0c --- /dev/null +++ b/src/Translumo/Services/AnkiService.cs @@ -0,0 +1,42 @@ +using System; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Translumo.Services +{ + public class AnkiService + { + private readonly HttpClient client; + private readonly string url = "http://127.0.0.1:8765"; + + public AnkiService() + { + client = new HttpClient(); + } + + public async Task AddBasicNoteAsync(string front, string back, string deckName = "Default", string modelName = "Basic") + { + var payload = new + { + action = "addNote", + version = 6, + @params = new + { + note = new + { + deckName = deckName, + modelName = modelName, + fields = new { Front = front, Back = back }, + tags = new string[] { "translumo" } + } + } + }; + + var json = JsonSerializer.Serialize(payload); + var resp = await client.PostAsync(url, new StringContent(json, Encoding.UTF8, "application/json")); + resp.EnsureSuccessStatusCode(); + } + } +} diff --git a/src/Translumo/Services/ChatUITextMediator.cs b/src/Translumo/Services/ChatUITextMediator.cs index 9c12cb10..539faf9c 100644 --- a/src/Translumo/Services/ChatUITextMediator.cs +++ b/src/Translumo/Services/ChatUITextMediator.cs @@ -9,6 +9,7 @@ public class ChatUITextMediator : IChatTextMediator { public event EventHandler TextRaised; public event EventHandler ClearTextsRaised; + public event EventHandler TextWithOriginalRaised; public void SendText(string text, bool successful) { @@ -24,5 +25,10 @@ public void ClearTexts() { ClearTextsRaised?.RaiseOnUIThread(this); } + + public void SendText(string original, string translated) + { + TextWithOriginalRaised?.RaiseOnUIThread(this, new TranslatedWithOriginalEventArgs(original, translated, TextTypes.Translation)); + } } } diff --git a/src/Translumo/Services/TranslatedWithOriginalEventArgs.cs b/src/Translumo/Services/TranslatedWithOriginalEventArgs.cs new file mode 100644 index 00000000..65f56944 --- /dev/null +++ b/src/Translumo/Services/TranslatedWithOriginalEventArgs.cs @@ -0,0 +1,18 @@ +using System; + +namespace Translumo.Services +{ + public class TranslatedWithOriginalEventArgs : EventArgs + { + public string Original { get; set; } + public string Translated { get; set; } + public Translumo.Infrastructure.TextTypes TextType { get; set; } + + public TranslatedWithOriginalEventArgs(string original, string translated, Translumo.Infrastructure.TextTypes textType) + { + Original = original; + Translated = translated; + TextType = textType; + } + } +} diff --git a/src/Translumo/Translumo.csproj b/src/Translumo/Translumo.csproj index 3646bc4f..b190913e 100644 --- a/src/Translumo/Translumo.csproj +++ b/src/Translumo/Translumo.csproj @@ -1,148 +1,10 @@ - - - - true - - - - WinExe - net8.0-windows10.0.19041.0 - true - app.manifest - win-x64 - en-US;en - true - true - Resources\Icons\favicon.ico - false - - - - true - true - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - True - True - IconsResource.resx - - - - - - ResXFileCodeGenerator - IconsResource.Designer.cs - - - - - - PreserveNewest - - - - - - $(DefaultXamlRuntime) - Designer - - - $(DefaultXamlRuntime) - Designer - - - - - - - - +*** Begin Patch +*** Update File: src/Translumo/Translumo.csproj +@@ + + WinExe + net8.0-windows10.0.19041.0 + true ++ true + app.manifest +*** End Patch diff --git a/src/Translumo/UI/TranslationOverlay.xaml b/src/Translumo/UI/TranslationOverlay.xaml new file mode 100644 index 00000000..7b373ea8 --- /dev/null +++ b/src/Translumo/UI/TranslationOverlay.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + +