Skip to content

Focus timer on watchOS#149

Merged
amikhaylin merged 13 commits intomasterfrom
watch-timer
Oct 20, 2025
Merged

Focus timer on watchOS#149
amikhaylin merged 13 commits intomasterfrom
watch-timer

Conversation

@amikhaylin
Copy link
Copy Markdown
Owner

  • fixes

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review by ChatGPT

list: $selectedSideBarItem,
title: selectedSideBarItem!.name)
.environmentObject(showInspector)
.environmentObject(selectedTasks)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваши изменения демонстрируют прогресс, однако есть несколько моментов, на которые стоит обратить внимание:

  1. Использование $selectedSideBarItem вместо selectedSideBarItem!:

    • Плюсы: Передача биндинга ($selectedSideBarItem) вместо принудительного развертывания (!) улучшает безопасность кода, предотвращая возможные краши, если значение окажется nil.
    • Минусы: Необходимо убедиться, что TasksListView ожидает Binding для параметра list. Если TasksListView изначально предполагал получение значения, а не биндинга, это приведет к несоответствию типов. Проверьте сигнатуру TasksListView и убедитесь, что она поддерживает получение биндинга.
  2. Изменение высоты фрейма с 270 на 300:

    • Увеличение высоты может быть оправдано, если это улучшает пользовательский интерфейс. Однако стоит убедиться, что новое значение не нарушает общую компоновку и адаптивность интерфейса для различных размеров экранов.
    • Рекомендуется рассмотреть использование относительных размеров или динамических значений, чтобы интерфейс был более гибким. Например, можно использовать GeometryReader для адаптации высоты в зависимости от доступного пространства.
  3. Повторяющиеся изменения в нескольких случаях switch selectedSideBarItem:

    • Убедитесь, что такие изменения согласованы во всех случаях и не влияют негативно на логику отображения задач для разных категорий (.inbox, .today, .tomorrow, .alltasks).
    • Рассмотрите возможность рефакторинга кода для уменьшения дубликации. Например, можно вынести общие параметры в отдельную функцию или использовать более абстрактный подход к конфигурации TasksListView.
  4. Отсутствие комментариев при значительных изменениях:

    • Хотя вы и не просили комментировать работающий код, важно документировать изменения, особенно если они влияют на общую логику приложения. Это поможет другим разработчикам понять мотивацию изменений и избежать потенциальных недоразумений.
  5. Проверка на nil после изменения на биндинг:

    • Если selectedSideBarItem может быть nil, убедитесь, что соответствующие представления корректно обрабатывают этот случай. Использование биндинга требует, чтобы состояние было всегда актуальным и валидным.

Рекомендации:

  • Проведите тщательное тестирование изменений, особенно того, как TasksListView обрабатывает биндинг вместо значения.
  • Рассмотрите возможность использования более гибких методов установки размеров интерфейса.
  • Думайте о рефакторинге для уменьшения дубликации кода и повышения его читаемости.

Эти улучшения помогут сделать код более устойчивым, поддерживаемым и адаптивным к будущим изменениям.

static func play() {
AudioServicesPlaySystemSound(SystemSoundID(1002))
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваш код в целом прост и функционален, однако есть несколько моментов, которые можно улучшить для повышения качества и соответствия современным практикам разработки на Swift/SwiftUI:

  1. Использование устаревшего фреймворка AudioToolbox:

    • AudioToolbox является более низкоуровневым API и считается устаревшим для современных приложений. Рекомендуется использовать AVFoundation, который предоставляет более гибкие и мощные возможности для работы со звуком.
    • Рекомендация:
      import AVFoundation
      
      struct FocusSounds {
          private static var audioPlayer: AVAudioPlayer?
      
          static func play() {
              guard let url = Bundle.main.url(forResource: "focusSound", withExtension: "mp3") else { return }
              do {
                  audioPlayer = try AVAudioPlayer(contentsOf: url)
                  audioPlayer?.play()
              } catch {
                  print("Ошибка воспроизведения звука: \(error.localizedDescription)")
              }
          }
      }
  2. Жестко закодированный идентификатор системного звука (SystemSoundID(1002)):

    • Использование магических чисел может привести к непредвиденным ошибкам и затруднить понимание кода. Лучше использовать понятные названия или загружать собственные звуковые файлы.
    • Рекомендация: Загружать собственные звуки из ресурсов приложения, как показано в примере выше.
  3. Отсутствие обработки ошибок:

    • В текущей реализации нет обработки возможных ошибок при воспроизведении звука. Это может привести к тому, что ошибки останутся неотловленными и усложнят отладку.
    • Рекомендация: Добавить обработку ошибок, чтобы можно было отследить и реагировать на возможные проблемы при воспроизведении звука.
  4. Одновременное воспроизведение нескольких звуков:

    • При использовании AudioServicesPlaySystemSound вы ограничены возможностью одновременного воспроизведения нескольких звуков. Использование AVAudioPlayer предоставляет больше контроля над воспроизведением.
    • Рекомендация: Если приложение требует воспроизведения нескольких звуков одновременно или более сложного управления звуками, AVAudioPlayer будет более подходящим выбором.
  5. Расширяемость и гибкость:

    • Текущая структура FocusSounds ограничена одним звуком. Если в будущем потребуется добавить больше звуков, структура может стать менее удобной.
    • Рекомендация: Рассмотреть возможность использования перечислений или других структур данных для управления несколькими звуками. Например:
      import AVFoundation
      
      struct FocusSounds {
          enum Sound: String {
              case focus = "focusSound"
              case alert = "alertSound"
              // Добавьте другие звуки по мере необходимости
          }
      
          private static var audioPlayer: AVAudioPlayer?
      
          static func play(sound: Sound) {
              guard let url = Bundle.main.url(forResource: sound.rawValue, withExtension: "mp3") else { return }
              do {
                  audioPlayer = try AVAudioPlayer(contentsOf: url)
                  audioPlayer?.play()
              } catch {
                  print("Ошибка воспроизведения звука: \(error.localizedDescription)")
              }
          }
      }
  6. Асинхронность:

    • В текущей реализации воспроизведение звука происходит синхронно, что может блокировать основной поток, если звук большой или загрузка занимает время.
    • Рекомендация: Рассмотреть возможность выполнения воспроизведения звука в фоновом потоке, чтобы избежать блокировки пользовательского интерфейса.

Итог: Рекомендуется перейти на использование AVFoundation для более гибкого и современного управления звуками, избежать использования магических чисел путем загрузки собственных звуковых файлов, а также улучшить обработку ошибок и расширяемость кода.

FocusTabItemView(tab: $tab)
FocusTabItemView()
.environmentObject(timer)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваш код в целом выглядит хорошо, однако есть несколько моментов, которые стоит обратить внимание для улучшения качества и предотвращения потенциальных проблем:

  1. Удаление @Binding var tab: MainViewTabs:

    • Вопрос: Убедитесь, что tab больше не используется внутри FocusTabItemView. Если ранее этот биндинг использовался для управления состоянием вкладки, удаление может привести к потере функциональности.
    • Рекомендация: Если управление вкладкой всё ещё необходимо, рассмотрите возможность использования другого подхода, например, через Environment или ObservableObject.
  2. Условная компиляция для watchOS:

    #if os(watchOS)
    Text("Focus")
    #endif
    • Комментарий: Хорошо, что вы учитываете платформозависимые особенности. Однако убедитесь, что этот текст необходим именно на watchOS и не влияет на другие платформы.
    • Рекомендация: Проверьте, отображается ли текст "Focus" адекватно на watchOS и нет ли необходимости в дополнительной стилизации или адаптации.
  3. Изменение системного изображения:

    Image(systemName: "brain.head.profile")
    • Комментарий: Замена иконки с "target" на "brain.head.profile" может улучшить интуитивное понимание состояния работы.
    • Рекомендация: Убедитесь, что новая иконка хорошо воспринимается пользователями и соответствует общей стилистике приложения. Можно также добавить локализацию или альтернативные изображения для разных контекстов.
  4. Обновление #Preview:

    FocusTabItemView()
        .environmentObject(timer)
    • Комментарий: Удаление биндинга tab из превью упрощает тестирование, однако если FocusTabItemView раньше использовал tab, возможно, некоторые состояния больше не проверяются в превью.
    • Рекомендация: Добавьте необходимые состояния или используйте фиктивные данные для tab, если это всё ещё необходимо для полноты тестирования компонента.
  5. Общие рекомендации:

    • Тестирование: После внесённых изменений протестируйте приложение на всех поддерживаемых платформах (включая watchOS), чтобы убедиться в корректности отображения и функциональности.
    • Документация: Обновите комментарии и документацию, если были внесены существенные изменения в логику компонента.
    • Код-стайл: Убедитесь, что все изменения соответствуют принятому стилю кодирования в вашем проекте для поддержания консистентности.

Внедрив эти рекомендации, вы улучшите качество кода и обеспечите стабильность функциональности вашего компонента.

.environmentObject(focusTask)
} else {
ZStack {
VStack {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваши изменения в коде демонстрируют попытку упростить передачу данных между представлениями. Однако, есть несколько аспектов, которые стоит рассмотреть для улучшения и избежания потенциальных проблем:

  1. Передача focusTask через environmentObject:

    • Преимущества: Использование environmentObject может упростить доступ к общим данным в глубоко вложенных представлениях, избегая необходимости передавать зависимости через множество уровней.
    • Недостатки: Чрезмерное использование environmentObject может привести к тому, что зависимости станут неявными, усложняя понимание структуры данных и их потоков. Это также может затруднить тестирование компонентов.

    Рекомендация: Убедитесь, что focusTask действительно является общим для многих представлений и оправдывает использование environmentObject. Если он используется только в ограниченном контексте, возможно, лучше оставить передачу через @Binding.

  2. Изменение сигнатуры FocusTasksView:

    • Было: FocusTasksView(selectedTask: $focusTask.task, viewMode: $viewMode)
    • Стало: FocusTasksView(viewMode: $viewMode).environmentObject(focusTask)

    Вопросы:

    • Убедитесь, что FocusTasksView корректно обрабатывает изменения в viewMode и может получить доступ к focusTask через environmentObject.
    • Проверьте, что ранее передаваемый selectedTask через @Binding не используется внутри FocusTasksView напрямую. Если он заменяется доступом через EnvironmentObject, необходимо обновить соответствующую логику внутри FocusTasksView.

    Рекомендация: Проведите тщательное тестирование FocusTasksView после внесения изменений, чтобы убедиться, что все зависимости корректно работают и данные синхронизируются как ожидалось.

  3. Организация модификаторов:

    FocusTasksView(viewMode: $viewMode)
        .environmentObject(timer)
        .environmentObject(focusTask)
    • Рассмотрите возможность группировки модификаторов для улучшения читаемости. Например, можно использовать цепочку вызовов или разделить модификаторы на логические блоки.
  4. Документация и комментарии:

    • Добавьте комментарии, объясняющие причину изменений, особенно если вы переходите с передачи через @Binding на environmentObject. Это поможет другим разработчикам понять намерения и контекст изменений.
  5. Проверка соответствия MVVM или выбранной архитектуре:

    • Убедитесь, что изменения соответствуют общей архитектуре приложения. Например, если вы придерживаетесь паттерна MVVM, проверьте, что focusTask находится в правильном месте (ViewModel) и что представления получают данные согласно архитектурным принципам.
  6. Обработка возможных ошибок:

    • При использовании environmentObject важно убедиться, что представления, которые его ожидают, получают его корректно. Рассмотрите добавление проверок или использование @EnvironmentObject с безопасными методами инициализации, чтобы избежать сбоев в случае отсутствия объекта в окружении.

Заключение:
Ваши изменения могут повысить гибкость и упростить передачу данных, но важно тщательно проверить их влияние на структуру приложения, поддерживаемость и тестируемость. Рекомендуется провести ревизию всех связанных компонентов, чтобы убедиться в корректности и эффективности внесённых изменений.

}
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваше изменение содержит несколько важных моментов, однако имеются некоторые недочёты, которые стоит учесть:

  1. Неправильная версия iOS в условии @available:
    В текущий момент последняя выпущенная версия iOS — 17.0. Проверка на доступность функции для iOS 26.0 приведёт к тому, что код внутри блока if #available(iOS 26.0, *) никогда не будет выполнен на существующих устройствах. Возможно, имелась в виду другая версия, например, iOS 16.0.

    Рекомендация:
    Проверьте правильность версии iOS и скорректируйте условие. Например:

    if #available(iOS 16.0, *) {
        // ваш код
    } else {
        // альтернативный код
    }
  2. Дублирование кода:
    В текущей реализации код для проверки доступности iOS дублируется внутри обоих веток условия if condition. Это снижает читаемость и увеличивает вероятность ошибок при дальнейшем изменении кода.

    Рекомендация:
    Попробуйте сначала проверить доступность iOS, а затем уже на основе условия condition выбирать стиль кнопки. Например:

    func body(content: Content) -> some View {
        if #available(iOS 16.0, *) {
            content.buttonStyle(condition ? .glassProminent : .glass)
        } else {
            content.buttonStyle(condition ? .borderedProminent : .bordered)
        }
    }
  3. Использование нестандартных стилей кнопок:
    Убедитесь, что .glass и .glassProminent действительно существуют и поддерживаются в той версии iOS, для которой вы добавляете проверку доступности. Если это кастомные стили, убедитесь, что они правильно реализованы.

  4. Расширяемость:
    Если в будущем появятся новые стили кнопок или потребуется поддержка других версий iOS, текущая структура может затруднить внесение изменений.

    Рекомендация:
    Рассмотрите возможность использования более гибкого подхода, например, определения стиля кнопки через вычисляемое свойство или отдельный метод, что улучшит читаемость и облегчает поддержку кода.

Пример улучшенного кода с учётом рекомендаций:

struct ConditionalButtonStyle: ViewModifier {
    let condition: Bool

    func body(content: Content) -> some View {
        let style: ButtonStyle
        if #available(iOS 16.0, *) {
            style = condition ? .glassProminent : .glass
        } else {
            style = condition ? .borderedProminent : .bordered
        }
        return content.buttonStyle(style)
    }
}

Этот подход уменьшает дублирование и повышает читаемость кода.

CURRENT_PROJECT_VERSION = 74;
DEAD_CODE_STRIPPING = YES;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Здравствуйте!

Спасибо за предоставленный пулл-реквест. Провёл тщательный анализ изменений в файлах проекта Xcode. Вот мои замечания и рекомендации:

  1. Удаление множества PBXBuildFile и PBXFileReference записей:

    • Потенциальные проблемы: Удаление этих записей может привести к отсутствию необходимых файлов в вашем проекте. Убедитесь, что эти файлы действительно не используются нигде в коде или ресурсах.
    • Рекомендация: Проверьте, что удалённые файлы не требуются для сборки или выполнения приложения. Возможно, стоит сначала закомментировать их удаление и проверить работоспособность проекта.
  2. Добавление новых PBXFileSystemSynchronizedBuildFileExceptionSet:

    • Потенциальные проблемы: Внесение изменений в систему синхронизации файлов может вызвать конфликты или проблемы с кэшированием Xcode. Убедитесь, что новые исключения корректны и необходимы для структуры вашего проекта.
    • Рекомендация: Проверьте, нет ли дублирующихся или конфликтующих исключений. Также убедитесь, что все пути в membershipExceptions правильные и соответствуют реальному расположению файлов.
  3. Изменение PBXFileSystemSynchronizedRootGroup:

    • Потенциальные проблемы: Перенос или изменение групп может повлиять на организацию файлов в Xcode. Это может быть проблемой для совместной работы, если другие разработчики не синхронизируют свои проекты должным образом.
    • Рекомендация: Убедитесь, что новая структура групп понятна и логична для всей команды. Возможно, стоит добавить описание изменений в документацию проекта.
  4. Обновление CURRENT_PROJECT_VERSION с 69 до 74:

    • Потенциальные проблемы: Изменение версии проекта должно соответствовать реальным изменениям и быть согласовано с другими процессами CI/CD, если они используются.
    • Рекомендация: Убедитесь, что увеличение версии проекта отражает значимые изменения и что все зависимости и системы сборки обновлены соответственно.
  5. Удаление групп CustomViews, Review, Utils и других:

    • Потенциальные проблемы: Эти группы могут содержать важные файлы, используемые в разных частях приложения. Их удаление может привести к ошибкам компиляции или отсутствию функционала.
    • Рекомендация: Проверьте, что все файлы внутри этих групп больше не используются. Если они всё ещё необходимы, убедитесь, что пути к ним обновлены правильно и они добавлены обратно в соответствующие фазы сборки.
  6. Общие рекомендации:

    • Тестирование: После внесения изменений обязательно протестируйте проект на всех целевых платформах (iOS, macOS, watchOS и т.д.), чтобы убедиться в отсутствии регрессий.
    • Ревью команды: Рекомендуется провести коллективный ревью с участием других членов команды, чтобы удостовериться в необходимости и корректности внесённых изменений.
    • Резервные копии: Перед внесением таких масштабных изменений стоит создать резервную копию текущей версии проекта или использовать ветку для безопасного тестирования.

Если у вас есть дополнительные вопросы или требуется помощь с конкретными частями проекта, пожалуйста, дайте знать!

Спасибо!

list: $selectedSideBarItem,
title: selectedSideBarItem!.name)
.environmentObject(showInspector)
.environmentObject(selectedTasks)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваши изменения демонстрируют стремление улучшить управление состоянием через использование привязок (Binding). Однако есть несколько моментов, которые стоит учесть для повышения надежности и читаемости кода:

  1. Использование Привязок (Binding):

    • Вы заменили передачу значения selectedSideBarItem! на привязку $selectedSideBarItem. Убедитесь, что в TasksListView параметр list действительно ожидает Binding<SideBarItem> (или соответствующий тип). Если TasksListView ожидает обычное значение, это приведет к ошибкам компиляции.
    • Если selectedSideBarItem остается опциональным, стоит рассмотреть безопасное извлечение вместо принудительного разворачивания. Например, использовать selectedSideBarItem?.name или предусмотреть дефолтное значение, чтобы избежать возможных крашей:
    title: selectedSideBarItem?.name ?? "Default Title"
  2. Безопасность Разворачивания Опционалов:

    • В текущем варианте вы по-прежнему используете selectedSideBarItem!.name, что может привести к крашам, если selectedSideBarItem будет nil. Рекомендуется использовать безопасные способы разворачивания:
    if let item = selectedSideBarItem {
        TasksListView(predicate: ..., list: $selectedSideBarItem, title: item.name)
    } else {
        // Обработка случая, когда selectedSideBarItem == nil
    }
  3. Изменение Высоты frame:

    • Вы изменили высоту frame с 150 на 170. Убедитесь, что это изменение не нарушает адаптивность интерфейса на разных устройствах и ориентациях. Возможно, стоит использовать относительные размеры или адаптивные конструкции, такие как GeometryReader, для обеспечения гибкости интерфейса.
  4. Повторяющийся Код:

    • В нескольких местах вы используете схожие конструкции для разных кейсов (.inbox, .today, и т.д.). Рассмотрите возможность вынесения общего кода в отдельный метод или вью для повышения читаемости и уменьшения дублирования.
    private func tasksListView(for predicate: NSPredicate, title: String) -> some View {
        TasksListView(predicate: predicate, list: $selectedSideBarItem, title: title)
            .environmentObject(showInspector)
            .environmentObject(selectedTasks)
    }
    
    // Использование:
    switch selectedSideBarItem {
    case .inbox:
        tasksListView(for: TasksQuery.predicateInbox(), title: selectedSideBarItem?.name ?? "Inbox")
    // остальные кейсы...
    }
  5. Управление Состоянием:

    • Убедитесь, что использование @EnvironmentObject для showInspector и selectedTasks оправдано и эти объекты действительно необходимы на данном уровне иерархии вью. Возможно, стоит пересмотреть уровень передачи этих объектов для улучшения инкапсуляции.
  6. Название Переменных:

    • Переменная list может быть не самым интуитивным названием для selectedSideBarItem. Рассмотрите использование более описательных названий, например, selectedItemBinding, чтобы повысить понятность кода.

В целом, ваши изменения направлены в правильное русло, но важно обеспечить безопасную работу с опционалами и согласованность типов при использовании привязок. Также рекомендуется рассмотреть возможности для рефакторинга для улучшения читаемости и поддерживаемости кода.

static func play() {
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_UserPreferredAlert))
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваш код выполняет базовую задачу воспроизведения системного звука, но есть несколько аспектов, которые можно улучшить для повышения его надежности и соответствия современным практикам разработки на Swift:

  1. Использование AudioToolbox vs AVFoundation:

    • AudioToolbox предоставляет базовые возможности для воспроизведения звуков, но AVFoundation предлагает более расширенные и гибкие функции для работы со звуком. Рассмотрите возможность использования AVFoundation для улучшения контроля над воспроизведением звуков и интеграции с другими медиафункциями вашего приложения.
    import AVFoundation
    
    struct FocusSounds {
        private static var audioPlayer: AVAudioPlayer?
    
        static func play() {
            guard let url = Bundle.main.url(forResource: "alert", withExtension: "wav") else { return }
            do {
                audioPlayer = try AVAudioPlayer(contentsOf: url)
                audioPlayer?.play()
            } catch {
                print("Не удалось воспроизвести звук: \(error.localizedDescription)")
            }
        }
    }
  2. Обработка ошибок:

    • Текущий код не обрабатывает возможные ошибки при воспроизведении звука. Это может затруднить отладку и ухудшить пользовательский опыт, если звук не будет воспроизводиться из-за ошибки.
  3. Гибкость выбора звуков:

    • Сейчас метод play() жестко привязан к системному звуку kSystemSoundID_UserPreferredAlert. Можно сделать метод более универсальным, позволяя передавать идентификатор звука или использовать собственные аудиофайлы.
    struct FocusSounds {
        static func play(soundID: SystemSoundID = kSystemSoundID_UserPreferredAlert) {
            AudioServicesPlaySystemSound(soundID)
        }
    }
  4. Асинхронное выполнение:

    • Если в будущем вы планируете добавлять более сложные операции при воспроизведении звука, стоит рассмотреть выполнение этих операций асинхронно, чтобы не блокировать основной поток.
  5. Документация и комментарии:

    • Добавьте документацию к вашему методу для лучшего понимания его назначения и использования другими разработчиками.
    /// Воспроизводит системный звук или заданный звук.
    /// - Parameter soundID: Идентификатор системного звука. По умолчанию `kSystemSoundID_UserPreferredAlert`.
    static func play(soundID: SystemSoundID = kSystemSoundID_UserPreferredAlert) {
        AudioServicesPlaySystemSound(soundID)
    }
  6. Управление звуковыми сессиями:

    • При использовании AVFoundation можно более тонко настраивать звуковую сессию, например, управлять режимами воспроизведения, что может быть полезно для вашего приложения.
  7. Совместимость и будущие обновления:

    • Убедитесь, что используемые API не устарели и будут поддерживаться в будущих версиях iOS. Следите за обновлениями документации Apple, чтобы своевременно адаптировать код.

Внедрение этих улучшений поможет сделать ваш код более надежным, гибким и соответствующим современным стандартам разработки на Swift.

// .applying(.init(hierarchicalColor: .blue))
.applying(.init(hierarchicalColor: .green))

let image = NSImage(systemSymbolName: "cup.and.saucer.fill", accessibilityDescription: nil)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Внесенные изменения улучшают визуальное представление интерфейса, однако есть несколько моментов, которые можно оптимизировать для повышения надежности и читаемости кода:

  1. Безопасное развертывание опционалов:
    Использование updateImage! может привести к аварийному завершению приложения, если image или withSymbolConfiguration вернут nil. Рекомендуется использовать безопасное развертывание через if let или guard:

    if let image = NSImage(systemSymbolName: "brain.head.profile", accessibilityDescription: nil),
       let updateImage = image.withSymbolConfiguration(configuration) {
        Image(nsImage: updateImage)
    } else {
        // Обработка случая, когда изображение не создано
    }
  2. Избегание дублирования кода:
    Конфигурация символа создается отдельно в обоих ветках if и else. Можно вынести создание конфигурации за пределы условного оператора, изменяя только необходимые параметры:

    let hierarchicalColor: NSImage.HierarchicalColor = (focusMode == .work) ? .red : .green
    let configuration = NSImage.SymbolConfiguration(pointSize: 16, weight: .light)
        .applying(.init(hierarchicalColor: hierarchicalColor))
  3. Удаление закомментированного кода:
    Закомментированные строки снижают читаемость кода. Если они не планируются к использованию в ближайшем будущем, их лучше удалить:

    -// .applying(.init(hierarchicalColor: .yellow))
    -// .applying(.init(hierarchicalColor: .blue))
  4. Описание доступности (Accessibility):
    Параметр accessibilityDescription установлен в nil. Для улучшения доступности рекомендуется предоставить информативное описание:

    let image = NSImage(systemSymbolName: "brain.head.profile", accessibilityDescription: "Иконка режима работы")
  5. Использование констант для магических чисел:
    Значение pointSize: 16 используется напрямую. Лучше вынести его в константу, чтобы облегчить возможные изменения и улучшить читаемость:

    let symbolPointSize: CGFloat = 16
    let configuration = NSImage.SymbolConfiguration(pointSize: symbolPointSize, weight: .light)
        .applying(.init(hierarchicalColor: hierarchicalColor))
  6. Проверка наличия символов:
    Убедитесь, что используемые символы ("brain.head.profile" и "cup.and.saucer.fill") поддерживаются всеми целевыми версиями macOS и корректно отображаются.

  7. Повышение читаемости конструкции if-else:
    Рассмотрите возможность использования switch или других структур для улучшения читаемости, особенно если количество режимов увеличится в будущем.

Применив вышеописанные рекомендации, вы улучшите надежность, поддерживаемость и читаемость кода, а также повысите качество пользовательского интерфейса и доступности приложения.

.environmentObject(focusTask)
} else {
ZStack {
VStack {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ваши изменения в коде демонстрируют стремление к улучшению управления состоянием и передаче зависимостей через environmentObject. Вот некоторые конструктивные замечания и предложения по улучшению:

  1. Изменение параметров и использование environmentObject:

    • Оригинальный код:
      FocusTasksView(selectedTask: $focusTask.task, viewMode: $viewMode)
    • Измененный код:
      FocusTasksView(viewMode: $viewMode)
          .id(refresher.refresh)
          .environmentObject(timer)
          .environmentObject(focusTask)
    • Замечание:
      • Передача focusTask через environmentObject может быть оправдана, если FocusTasksView и его дочерние представления часто используют focusTask. Однако, если focusTask используется только в FocusTasksView, предпочтительнее передавать его как отдельный @Binding параметр для явного управления состоянием.
      • Передача viewMode как @Binding параметра сохраняется, что хорошо, так как это позволяет изменять режим просмотра из дочернего представления.
  2. Использование .id(refresher.refresh):

    • Замечание:
      • Применение .id(refresher.refresh) вызывает пересоздание представления FocusTasksView при изменении refresher.refresh. Это может быть полезно для принудительного обновления представления, но стоит убедиться, что это действительно необходимо, так как частое пересоздание представлений может негативно сказаться на производительности.
      • Убедитесь, что refresher.refresh имеет уникальное и корректное значение, которое действительно сигнализирует о необходимости обновления.
  3. Передача timer через environmentObject:

    • Замечание:
      • Если timer нужен не только в FocusTasksView, но и в других частях иерархии представлений, использование environmentObject оправдано. В противном случае, рассмотрите возможность передачи timer как отдельного @ObservedObject или @StateObject, чтобы сделать зависимости более явными и облегчить тестирование.
  4. Общая организация:

    • Рекомендация:
      • Старайтесь поддерживать баланс между явной передачей зависимостей и использованием environmentObject. Чрезмерное использование environmentObject может затруднить отслеживание зависимостей и тестирование компонентов.
      • Документируйте, какие объекты передаются через environmentObject, чтобы другие разработчики могли легко понять структуру зависимости.
  5. Безопасность типов и управление состоянием:

    • Замечание:
      • Убедитесь, что focusTask и timer корректно инициализируются и управляются на уровне родительских представлений, чтобы избежать потенциальных сбоев или некорректного поведения.
      • Рассмотрите использование протоколов для предоставления зависимостей через environmentObject, что может повысить гибкость и тестируемость кода.

Вывод: Ваши изменения демонстрируют продуманный подход к управлению состоянием и зависимостями. Однако, рекомендуется тщательно оценить необходимость использования environmentObject для каждого из объектов и убедиться, что это не усложняет структуру приложения. Явная передача зависимостей может повысить читаемость и поддерживаемость кода.

@amikhaylin amikhaylin merged commit 81ce286 into master Oct 20, 2025
1 check passed
@amikhaylin amikhaylin deleted the watch-timer branch October 20, 2025 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant