Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: sanghyeok-kim/MultiTimer
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.6.0
Choose a base ref
...
head repository: sanghyeok-kim/MultiTimer
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
  • 19 commits
  • 21 files changed
  • 2 contributors

Commits on Aug 11, 2023

  1. Copy the full SHA
    326522a View commit details
  2. Copy the full SHA
    737a174 View commit details
  3. Merge pull request #53 from sanghyeok-kim/52-timer-time-edit-confirm-…

    …button-enable-bug
    
    타이머 편집시,  시간을 변경하지 않아도 '확인'버튼이 활성화되는 문제 해결
    sanghyeok-kim authored Aug 11, 2023
    Copy the full SHA
    a367617 View commit details
  4. Merge pull request #54 from sanghyeok-kim/51-timer-alarm-sound-edit-w…

    …hile-running-bug
    
    타이머를 실행한 뒤 알람음을 변경할 경우, 알람음 변경이 적용되지 않는 문제 해결
    sanghyeok-kim authored Aug 11, 2023
    Copy the full SHA
    c4e1a0c View commit details
  5. Copy the full SHA
    b9ca9e8 View commit details
  6. Copy the full SHA
    4198b87 View commit details
  7. Merge pull request #56 from sanghyeok-kim/55-asking-for-ratings

    평점 유도 기능 추가
    sanghyeok-kim authored Aug 11, 2023
    Copy the full SHA
    d0453e5 View commit details

Commits on Aug 12, 2023

  1. Copy the full SHA
    96222d9 View commit details
  2. Update README.md

    sanghyeok-kim authored Aug 12, 2023
    Copy the full SHA
    1b1c9fe View commit details

Commits on Sep 19, 2023

  1. Copy the full SHA
    056848d View commit details
  2. Copy the full SHA
    8a80c1b View commit details
  3. Copy the full SHA
    bfc7463 View commit details
  4. [Merge pull request] #58 from sanghyeok-kim/57-home-ui-improvement

    홈 화면의 UI 개선
    sanghyeok-kim authored Sep 19, 2023
    Copy the full SHA
    b985314 View commit details

Commits on Jan 28, 2024

  1. Copy the full SHA
    6d3f3ca View commit details
  2. Copy the full SHA
    c2123e6 View commit details
  3. Copy the full SHA
    9ff582c View commit details
  4. Copy the full SHA
    3690ab1 View commit details
  5. Merge pull request #62 from sanghyeok-kim/59-reset-all-confirm-alert

    타이머 모두 중지 기능에 대한 confirm alert를 추가합니다.
    sanghyeok-kim authored Jan 28, 2024
    Copy the full SHA
    37da081 View commit details
  6. Merge pull request #61 from sanghyeok-kim/60-rename-displayName

    영어, 일본어, 베트남어에 대한 CFBundleDisplayName 수정
    sanghyeok-kim authored Jan 28, 2024
    Copy the full SHA
    72f8504 View commit details
12 changes: 8 additions & 4 deletions Multimer/Multimer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
1E1869B32A8603D8000AFDC6 /* SKStoreReviewController+requestReviewInCurrentScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1869B22A8603D8000AFDC6 /* SKStoreReviewController+requestReviewInCurrentScene.swift */; };
1E1C42E22A765844003CC427 /* RingtoneSelectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1C42E12A765844003CC427 /* RingtoneSelectViewController.swift */; };
1E1C43662A7681FA003CC427 /* radar.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 1E1C43522A7681F8003CC427 /* radar.aiff */; };
1E1C43672A7681FA003CC427 /* alarm.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 1E1C43532A7681F9003CC427 /* alarm.aiff */; };
@@ -155,6 +156,7 @@
/* Begin PBXFileReference section */
02A9A991A8E30450D4458665 /* Pods_MultimerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MultimerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
09D9588E5DAECA7EB7A30024 /* Pods_Multimer_MultimerUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Multimer_MultimerUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1E1869B22A8603D8000AFDC6 /* SKStoreReviewController+requestReviewInCurrentScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SKStoreReviewController+requestReviewInCurrentScene.swift"; sourceTree = "<group>"; };
1E1C42DF2A760939003CC427 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = "<group>"; };
1E1C42E02A760939003CC427 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
1E1C42E12A765844003CC427 /* RingtoneSelectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RingtoneSelectViewController.swift; sourceTree = "<group>"; };
@@ -673,6 +675,7 @@
1E23D56A299A1110008FD287 /* UIView+shouldFadeIn.swift */,
1E744B97296C488A00CD824D /* UIStackView+addArrangedSubviews.swift */,
1E23D5362994BCF8008FD287 /* NotificationName+CustomName.swift */,
1E1869B22A8603D8000AFDC6 /* SKStoreReviewController+requestReviewInCurrentScene.swift */,
);
path = Extension;
sourceTree = "<group>";
@@ -1148,6 +1151,7 @@
1E744BB2296C488A00CD824D /* TimerFilteringCondition.swift in Sources */,
1E4CB4DF2966BE9000FC918E /* TimeMO+CoreDataClass.swift in Sources */,
1E744BB4296C488A00CD824D /* TimeType.swift in Sources */,
1E1869B32A8603D8000AFDC6 /* SKStoreReviewController+requestReviewInCurrentScene.swift in Sources */,
1E744BB8296C488A00CD824D /* SymbolImageButton.swift in Sources */,
1E8C28F42A73C0C100935C5E /* CoordinatorType.swift in Sources */,
1E23D56B299A1110008FD287 /* UIView+shouldFadeIn.swift in Sources */,
@@ -1390,11 +1394,11 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.6.0;
MARKETING_VERSION = 1.7.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sanghyeok.Multimer;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Multimer Development ProvisioningProfile";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MultimerProvisioningProfileForDevelopment;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
@@ -1424,11 +1428,11 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.6.0;
MARKETING_VERSION = 1.7.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sanghyeok.Multimer;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Multimer AppStore ProvisioningProfile";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MultimerProvisioningProfileForDistribution;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
3 changes: 3 additions & 0 deletions Multimer/Multimer/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
//

import UIKit
import StoreKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

@@ -24,6 +25,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {

window?.rootViewController = rootNavigationController
window?.makeKeyAndVisible()

SKStoreReviewController.requestReviewInCurrentScene()
}
}

28 changes: 26 additions & 2 deletions Multimer/Multimer/Data/Service/UserNotificationCenterService.swift
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ final class UserNotificationCenterService {
ringtone: Ringtone?,
remainingSeconds: TimeInterval,
timerName: String,
notificationIdentifier: String?
notificationIdentifier: String
) {
let content = UNMutableNotificationContent()
content.title = LocalizableString.appTitle.localized
@@ -28,12 +28,36 @@ final class UserNotificationCenterService {

if remainingSeconds <= .zero { return }
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: remainingSeconds, repeats: false)
guard let notificationIdentifier = notificationIdentifier else { return }
let request = UNNotificationRequest(identifier: notificationIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
}

static func removeNotification(withIdentifiers identifiers: [String]) {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: identifiers)
}

static func updateRingtone(for notificationIdentifier: String, remainingSeconds: Double, newRingtone: Ringtone?) {
let center = UNUserNotificationCenter.current()

center.getPendingNotificationRequests { requests in
guard let matchingRequest = requests.first(where: { $0.identifier == notificationIdentifier }) else { return }
guard let updatedContent = matchingRequest.content.mutableCopy() as? UNMutableNotificationContent else { return }

if let ringtoneFileName = newRingtone?.name, newRingtone != .default1 {
updatedContent.sound = UNNotificationSound(
named: UNNotificationSoundName(rawValue: "\(ringtoneFileName).\(Constant.Ringtone.extension)")
)
}

let updatedTrigger = UNTimeIntervalNotificationTrigger(timeInterval: remainingSeconds, repeats: false)
let updatedRequest = UNNotificationRequest(
identifier: notificationIdentifier,
content: updatedContent,
trigger: updatedTrigger
)

center.removePendingNotificationRequests(withIdentifiers: [notificationIdentifier])
center.add(updatedRequest)
}
}
}
4 changes: 2 additions & 2 deletions Multimer/Multimer/Domain/Model/Timer.swift
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ struct Timer {
var state: TimerState
var expireDate: Date?
var startDate: Date?
var notificationIdentifier: String?
var notificationIdentifier: String
var type: TimerType
var ringtone: Ringtone?
var index: Int
@@ -80,7 +80,7 @@ extension Timer: Equatable {
static func == (lhs: Timer, rhs: Timer) -> Bool {
return (lhs.name == rhs.name)
&& (lhs.tag == rhs.tag)
&& (lhs.time == rhs.time)
&& (lhs.time.totalSeconds == rhs.time.totalSeconds)
&& (lhs.ringtone == rhs.ringtone)
}
}
10 changes: 9 additions & 1 deletion Multimer/Multimer/Domain/UseCase/CountDownTimerUseCase.swift
Original file line number Diff line number Diff line change
@@ -116,6 +116,14 @@ final class CountDownTimerUseCase: TimerUseCase {
resetTimer()
}

if newTimer.ringtone != currentTimer.ringtone {
UserNotificationCenterService.updateRingtone(
for: currentTimer.notificationIdentifier,
remainingSeconds: currentTimer.remainingSeconds,
newRingtone: newTimer.ringtone
)
}

timerPersistentRepository
.updateTimer(
target: newTimer.identifier,
@@ -139,7 +147,7 @@ final class CountDownTimerUseCase: TimerUseCase {
dispatchSourceTimer?.cancel()
dispatchSourceTimer = nil

guard let notificationIdentifier = currentTimer.notificationIdentifier else { return }
let notificationIdentifier = currentTimer.notificationIdentifier
UserNotificationCenterService.removeNotification(withIdentifiers: [notificationIdentifier])
}

8 changes: 7 additions & 1 deletion Multimer/Multimer/Localizing/LocalizableString.swift
Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@ enum LocalizableString {
case cancel
case delete
case deleteConfirmMessage(count: Int)
case reset
case resetConfirmMessage
case noTimerCreatedMessage
case addTimerMessage
case noTimerActivatedMessage
@@ -69,7 +71,7 @@ enum LocalizableString {
return String(format: NSLocalizedString("activated", comment: ""))
case .enterTimerNameToCreate:
return String(format: NSLocalizedString("enterTimerNameToCreate", comment: ""))
case . enterStopwatchNameToCreate:
case .enterStopwatchNameToCreate:
return String(format: NSLocalizedString("enterStopwatchNameToCreate", comment: ""))
case .createTimer:
return String(format: NSLocalizedString("createTimer", comment: ""))
@@ -85,6 +87,10 @@ enum LocalizableString {
return String(format: NSLocalizedString("delete", comment: ""))
case .deleteConfirmMessage(let count):
return String(format: NSLocalizedString("deleteConfirmMessage", comment: ""), arguments: [count])
case .reset:
return String(format: NSLocalizedString("reset", comment: ""))
case .resetConfirmMessage:
return String(format: NSLocalizedString("resetConfirmMessage", comment: ""))
case .noTimerCreatedMessage:
return String(format: NSLocalizedString("noTimerCreatedMessage", comment: ""))
case .addTimerMessage:
2 changes: 1 addition & 1 deletion Multimer/Multimer/Localizing/en.lproj/InfoPlist.strings
Original file line number Diff line number Diff line change
@@ -6,4 +6,4 @@

*/

CFBundleDisplayName = "Multi+Timer";
CFBundleDisplayName = "MultiTimer";
2 changes: 2 additions & 0 deletions Multimer/Multimer/Localizing/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
"done" = "Done";
"deleteConfirmMessage" = "Are you sure to delete the %d timer(s)?";
"deleteTimer" = "Delete Timer";
"reset" = "Reset";
"resetConfirmMessage" = "Are you sure to reset all activated timers?";
"cancel" = "Cancel";
"delete" = "Delete";
"noTimerCreatedMessage" = "No Timer Created";
2 changes: 1 addition & 1 deletion Multimer/Multimer/Localizing/ja.lproj/InfoPlist.strings
Original file line number Diff line number Diff line change
@@ -6,4 +6,4 @@

*/

CFBundleDisplayName = "マルチ+タイマー";
CFBundleDisplayName = "マルチタイマー";
2 changes: 2 additions & 0 deletions Multimer/Multimer/Localizing/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
"done" = "完了";
"deleteConfirmMessage" = "本当に%dつのタイマーを削除しますか?";
"deleteTimer" = "タイマーを削除";
"reset" = "リセット";
"resetConfirmMessage" = "全ての%d個の活性化されたタイマーをリセットしますか?";
"cancel" = "キャンセル";
"delete" = "削除";
"noTimerCreatedMessage" = "作成されたタイマーなし";
2 changes: 2 additions & 0 deletions Multimer/Multimer/Localizing/ko.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
"done" = "완료";
"deleteConfirmMessage" = "선택한 %d개의 타이머를 삭제하시겠습니까?";
"deleteTimer" = "타이머 삭제";
"reset" = "중지";
"resetConfirmMessage" = "활성화된 타이머를 모두 중지하시겠습니까?";
"cancel" = "취소";
"delete" = "삭제";
"noTimerCreatedMessage" = "생성된 타이머 없음";
2 changes: 2 additions & 0 deletions Multimer/Multimer/Localizing/ru.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
"done" = "Готово";
"deleteConfirmMessage" = "Вы уверены, что хотите удалить выбранные %d таймеров?";
"deleteTimer" = "Удалить таймер";
"reset" = "Сбросить";
"resetConfirmMessage" = "Вы уверены, что хотите сбросить все активированные таймеры?";
"cancel" = "Отменить";
"delete" = "Удалить";
"noTimerCreatedMessage" = "Таймер не создан";
2 changes: 1 addition & 1 deletion Multimer/Multimer/Localizing/vi.lproj/InfoPlist.strings
Original file line number Diff line number Diff line change
@@ -6,4 +6,4 @@

*/

CFBundleDisplayName = "Multi Timer";
CFBundleDisplayName = "MultiTimer";
2 changes: 2 additions & 0 deletions Multimer/Multimer/Localizing/vi.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
"done" = "Xong";
"deleteConfirmMessage" = "Bạn có chắc chắn muốn xóa %d cái hẹn giờ đã chọn không?";
"deleteTimer" = "Xóa hẹn giờ";
"reset" = "Đặt lại";
"resetConfirmMessage" = "Bạn có chắc chắn muốn đặt lại tất cả bộ hẹn giờ đã kích hoạt không";
"cancel" = "Hủy";
"delete" = "Xóa";
"noTimerCreatedMessage" = "Không có bộ hẹn giờ nào\nđã được tạo";
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
"done" = "完成";
"deleteConfirmMessage" = "您真的要删除%d个计时器吗?";
"deleteTimer" = "删除计时器";
"reset" = "重置";
"resetConfirmMessage" = "您确定要重置所有激活的计时器吗?";
"cancel" = "取消";
"delete" = "删除";
"noTimerCreatedMessage" = "无创建定时器";
23 changes: 22 additions & 1 deletion Multimer/Multimer/Presentation/Home/HomeViewController.swift
Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@
// Created by 김상혁 on 2022/11/02.
//

import RxSwift
import RxRelay
import RxAppState
import RxSwift

final class HomeViewController: UIViewController, ViewType {

@@ -181,6 +181,15 @@ final class HomeViewController: UIViewController, ViewType {
}
.disposed(by: disposeBag)

output.showResetAllConfirmAlert
.withUnretained(self)
.bind { `self`, _ in
self.showResetAllTimersConfirmAlert(confirmHandler: { _ in
viewModel.input.confirmResetAllButtonDidTap.accept(())
})
}
.disposed(by: disposeBag)

output.hideResetAllActiveTimersButton
.observe(on: MainScheduler.asyncInstance)
.withUnretained(self)
@@ -296,6 +305,18 @@ private extension HomeViewController {
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}

func showResetAllTimersConfirmAlert(confirmHandler: @escaping (UIAlertAction) -> Void) {
let resetAllTimerString = LocalizableString.resetAll.localized
let resetConfirmMessageString = LocalizableString.resetConfirmMessage.localized
let cancelString = LocalizableString.cancel.localized
let resetString = LocalizableString.reset.localized

let alert = UIAlertController(title: resetAllTimerString, message: resetConfirmMessageString, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: cancelString, style: .default))
alert.addAction(UIAlertAction(title: resetString, style: .destructive, handler: confirmHandler))
present(alert, animated: true, completion: nil)
}
}

// MARK: - Notification Center Methods
9 changes: 9 additions & 0 deletions Multimer/Multimer/Presentation/Home/HomeViewModel.swift
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ final class HomeViewModel: ViewModelType {
let timerControlButtonInEditViewDidTap = PublishRelay<EditViewButtonType>()
let deleteButtonInEditViewDidTap = PublishRelay<Void>()
let confirmDeleteButtonDidTap = PublishRelay<Void>()
let confirmResetAllButtonDidTap = PublishRelay<Void>()
let resetAllActiveTimersButtonDidTap = PublishRelay<Void>()
}

@@ -31,6 +32,7 @@ final class HomeViewModel: ViewModelType {
let maintainEditingMode = PublishRelay<Bool>()
let enableEditViewButtons = PublishRelay<Bool>()
let showDeleteConfirmAlert = PublishRelay<Int>()
let showResetAllConfirmAlert = PublishRelay<Void>()
let showNotificationAuthAlert = PublishRelay<Void>()
let deselectRows = PublishRelay<[Int]>()
let hideResetAllActiveTimersButton = BehaviorRelay<Bool>(value: true)
@@ -62,6 +64,7 @@ final class HomeViewModel: ViewModelType {
handleCellDidMove()
handleAddTimerButtonDidTap()
handleResetAllActiveTimersButton()
handleComfirmResetAllActiveTimersButton()
handleEditButtonDidTap()
handleEventFromEditView(with: homeUseCase)

@@ -242,6 +245,12 @@ private extension HomeViewModel {

func handleResetAllActiveTimersButton() {
input.resetAllActiveTimersButtonDidTap
.bind(to: output.showResetAllConfirmAlert)
.disposed(by: disposeBag)
}

func handleComfirmResetAllActiveTimersButton() {
input.confirmResetAllButtonDidTap
.withLatestFrom(output.filteredTimerCellViewModels)
.bind { filteredCellViewModels in
filteredCellViewModels.forEach { $0.resetTimer() }
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ final class TimerViewCell: UITableViewCell, CellIdentifiable, ViewType {

override func layoutSubviews() {
super.layoutSubviews()
contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 2, left: 4, bottom: 2, right: 4))
contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 2.5, left: 5.5, bottom: 2.5, right: 5.5))
}

override func prepareForReuse() {
Loading