) {
96 | let x = targetContentOffset.pointee.x
97 | pageControl.currentPage = Int(round(x / view.frame.width))
98 | }
99 | }
100 |
101 | // MARK: - CollectionView UICollectionViewDelegateFlowLayout
102 | extension TutorialViewController: UICollectionViewDelegateFlowLayout {
103 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
104 | return collectionView.frame.size
105 | }
106 |
107 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
108 | return CGFloat.leastNonzeroMagnitude
109 | }
110 |
111 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
112 | return CGFloat.leastNonzeroMagnitude
113 | }
114 |
115 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
116 | return UIEdgeInsets(top: .zero, left: .zero, bottom: .zero, right: .zero)
117 | }
118 | }
119 |
120 | // MARK: - Draw
121 | private extension TutorialViewController {
122 | private func draw() {
123 | view.addSubview(actionView)
124 | actionView.snp.makeConstraints {
125 | $0.left.right.equalToSuperview()
126 | $0.bottom.equalToSuperview()
127 | }
128 |
129 | actionView.addSubview(actionButton)
130 | actionButton.snp.makeConstraints {
131 | $0.left.equalToSuperview().offset(16)
132 | $0.right.equalToSuperview().offset(-16)
133 | $0.height.equalTo(48)
134 | $0.top.equalToSuperview().offset(16)
135 | $0.bottom.equalTo(actionView.safeAreaLayoutGuide.snp.bottom)
136 | }
137 |
138 | view.addSubview(pageControl)
139 | pageControl.snp.makeConstraints {
140 | $0.left.right.equalToSuperview()
141 | $0.centerX.equalToSuperview()
142 | $0.height.equalTo(16)
143 | $0.bottom.equalTo(actionView.snp.top).offset(-8)
144 | }
145 |
146 | view.addSubview(collectionView)
147 | collectionView.snp.makeConstraints {
148 | $0.top.left.right.equalToSuperview()
149 | $0.bottom.equalTo(pageControl.snp.top).offset(-8)
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/AppSeed/Scenes/Tutorial/TutorialViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewModelTemplate.swift
3 | // AppSeed
4 | //
5 | // Created by Tunay Alver on 17.11.2024.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - Source
11 | protocol TutorialViewModelDataSource {
12 | var models: [TutorialUIModel] { get }
13 | }
14 |
15 | // MARK: - Closure
16 | protocol TutorialViewModelClosureSource {
17 | var completedClosure: EmptyClosure? { get set }
18 | }
19 |
20 | // MARK: - Function
21 | protocol TutorialViewModelFunctionSource {
22 | func numberOfItems() -> Int
23 | func getTutorial(_ index: Int) -> TutorialUIModel
24 | }
25 |
26 | // MARK: - Protocol
27 | protocol TutorialViewModelProtocol: BaseViewModel, TutorialViewModelDataSource, TutorialViewModelClosureSource, TutorialViewModelFunctionSource { }
28 |
29 | // MARK: - ViewModel
30 | final class TutorialViewModel: BaseViewModel, TutorialViewModelProtocol {
31 | // MARK: - Source
32 | var models: [TutorialUIModel] = TutorialUIModel.getTutorialData()
33 |
34 | // MARK: - Closure
35 | var completedClosure: EmptyClosure?
36 |
37 | // MARK: - Function
38 | func numberOfItems() -> Int {
39 | return models.count
40 | }
41 |
42 | func getTutorial(_ index: Int) -> TutorialUIModel {
43 | return models[index]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/AppSeed/Scenes/Tutorial/UIModel/TutorialUIModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TutorialUIModel.swift
3 | // AppSeed
4 | //
5 | // Created by tunay alver on 24.11.2024.
6 | //
7 |
8 | import Foundation
9 |
10 | struct TutorialUIModel {
11 | let image: TutorialImage?
12 | let title: String?
13 | let subtitle: String?
14 | }
15 |
16 | // MARK: - Models
17 | extension TutorialUIModel {
18 | static func getTutorialData() -> [TutorialUIModel] {
19 | let models = [
20 | TutorialUIModel(
21 | image: .tutorial_1,
22 | title: TutorialLocalizable.tutorial_title_1,
23 | subtitle: TutorialLocalizable.tutorial_subtitle_1
24 | ),
25 | TutorialUIModel(
26 | image: .tutorial_2,
27 | title: TutorialLocalizable.tutorial_title_2,
28 | subtitle: TutorialLocalizable.tutorial_subtitle_2
29 | ),
30 | TutorialUIModel(
31 | image: .tutorial_3,
32 | title: TutorialLocalizable.tutorial_title_3,
33 | subtitle: TutorialLocalizable.tutorial_subtitle_3
34 | )
35 | ]
36 |
37 | return models
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/AppSeed/UIComponents/View/HudView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HudView.swift
3 | // AppSeed
4 | //
5 | // Created by tunay alver on 4.01.2024.
6 | //
7 |
8 | import UIKit
9 | import Lottie
10 | import SnapKit
11 |
12 | final class HudView: UIView {
13 | // MARK: - Properties
14 | private lazy var lottieView: LottieAnimationView = {
15 | let view = LottieAnimationView(name: "lottie-loading")
16 | view.contentMode = .scaleAspectFit
17 | view.loopMode = .loop
18 | return view
19 | }()
20 |
21 | private lazy var logo: CircleImageView = {
22 | let view = CircleImageView(frame: .zero)
23 | view.image = Logo.logo_1024.image
24 | view.contentMode = .scaleAspectFit
25 | return view
26 | }()
27 |
28 | override init(frame: CGRect) {
29 | super.init(frame: frame)
30 | draw()
31 | prepare()
32 | lottieView.play()
33 | }
34 |
35 | required init?(coder aDecoder: NSCoder) {
36 | super.init(coder: aDecoder)
37 | draw()
38 | prepare()
39 | lottieView.play()
40 | }
41 |
42 | func prepare() {
43 | let backgroundColor = ColorBackground.backgroundPrimary.color
44 | self.backgroundColor = backgroundColor.withAlphaComponent(0.5)
45 | }
46 | }
47 |
48 | private extension HudView {
49 | private func draw() {
50 | addSubview(lottieView)
51 | lottieView.snp.makeConstraints { make in
52 | make.centerX.centerY.equalToSuperview()
53 | make.width.equalTo(80)
54 | make.height.equalTo(80)
55 | }
56 |
57 | addSubview(logo)
58 | logo.snp.makeConstraints { make in
59 | make.centerX.centerY.equalToSuperview()
60 | make.width.equalTo(40)
61 | make.height.equalTo(40)
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #  AppSeed
2 |
3 | This is a seed application designed for kickstarting new projects for Swift. Pull this repository and customize the necessary components to serve as a base for new applications. It includes various extensions, base classes, helpers, and packages curated for use in our projects.
4 |
5 | ## Usage
6 |
7 | To install and use AppSeed, follow these steps:
8 |
9 | 1. Clone the `develop` branch of this repository:
10 |
11 | ```bash
12 | git clone -b develop https://github.com/devno39/AppSeed.git
13 | ```
14 |
15 | 2. Install templates:
16 |
17 | ```bash
18 | cd ...PATH.../AppSeed/Templates
19 | ```
20 | ```bash
21 | swift install.swift
22 | ```
23 |
24 | 2. Rename to suit your project's name:
25 |
26 | ```bash
27 | cd ...PATH.../AppSeed/Renamer
28 | ```
29 | ```bash
30 | swift Renamer.swift AppSeed NewProjectName
31 | ```
32 |
33 |
34 | ### Contributing
35 |
36 | We welcome contributions to AppSeed. To contribute:
37 |
38 | 1. Open an issue with a clear title and detailed description.
39 | 2. For pull requests:
40 | - Name your branch using the format: `feature/issue39`. If there is no issue `feature/name_name` is just fine.
41 | - Make sure to open the pull request into the `develop` branch.
42 | - Reviews will be conducted before merging.
43 |
44 | ## Get in Touch
45 |
46 |
47 |
48 |
49 | @devno39
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Renamer/Renamer.swift:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env swift
2 |
3 | import Foundation
4 |
5 | final class Renamer: NSObject {
6 | // MARK: - Properties
7 | let fileManager = FileManager.default
8 | var processedPaths = [String]()
9 |
10 | var oldName: String
11 | let newName: String
12 |
13 | // MARK: - Init
14 | init(oldName: String, newName: String) {
15 | self.oldName = oldName
16 | self.newName = newName
17 | }
18 |
19 | // MARK: - API
20 | func run() {
21 | var currentPath = fileManager.currentDirectoryPath
22 | let scriptPath: URL = URL(fileURLWithPath: currentPath)
23 | var folderPath: URL = scriptPath.deletingLastPathComponent() // Go one level up
24 |
25 | print("Script is running in directory: \(folderPath.path)")
26 |
27 | if let oldProjectName = findOldProjectName(folderPath) {
28 | oldName = oldProjectName
29 | print("Old project name found: \(oldName). Processing continues.")
30 | } else {
31 | print("Error: Could not detect an .xcodeproj file in \(folderPath.path).")
32 | print("Please provide the old project name manually:")
33 | if let name = readLine(), !name.isEmpty {
34 | oldName = name
35 | } else {
36 | print("No project name entered. Exiting.")
37 | exit(1)
38 | }
39 | }
40 |
41 | if fileManager.changeCurrentDirectoryPath(folderPath.path) {
42 | print("\nSuccess: Changed to project directory.")
43 | currentPath = fileManager.currentDirectoryPath
44 | } else {
45 | print("Error: Could not change to project directory at \(folderPath.path). Exiting.")
46 | exit(1)
47 | }
48 |
49 | print("Current directory is \(currentPath)")
50 | print("\n------------------------------------------")
51 | print("Rename Xcode Project from [\(oldName)] to [\(newName)]")
52 | print("------------------------------------------\n")
53 |
54 | if validatePath(currentPath) {
55 | enumeratePath(currentPath)
56 | } else {
57 | print("Error: Xcode project or workspace with name [\(oldName)] not found.")
58 | exit(1)
59 | }
60 |
61 | print("\n------------------------------------------")
62 | print("Xcode Project Rename Finished!")
63 | print("------------------------------------------\n")
64 | }
65 |
66 | // MARK: - Helpers
67 | private func findOldProjectName(_ projectFolderPath: URL) -> String? {
68 | do {
69 | let directoryContents = try fileManager.contentsOfDirectory(at: projectFolderPath, includingPropertiesForKeys: nil, options: [])
70 | print("Searching for .xcodeproj in \(projectFolderPath.path)...")
71 | guard let projectFileName = directoryContents.filter({ $0.pathExtension == "xcodeproj" }).first?.deletingPathExtension().lastPathComponent else {
72 | return nil
73 | }
74 | return projectFileName
75 | } catch {
76 | print("Error reading directory contents: \(error.localizedDescription)")
77 | return nil
78 | }
79 | }
80 |
81 | private func validatePath(_ path: String) -> Bool {
82 | let projectPath = path.appending("/\(oldName).xcodeproj")
83 | let workspacePath = path.appending("/\(oldName).xcworkspace")
84 | let isValid = fileManager.fileExists(atPath: projectPath) || fileManager.fileExists(atPath: workspacePath)
85 | return isValid
86 | }
87 |
88 | private func enumeratePath(_ path: String) {
89 | let enumerator = fileManager.enumerator(atPath: path)
90 | while let element = enumerator?.nextObject() as? String {
91 | let itemPath = path.appending("/\(element)")
92 | if !processedPaths.contains(itemPath) && !shouldSkip(element) {
93 | processPath(itemPath)
94 | }
95 | }
96 | }
97 |
98 | private func processPath(_ path: String) {
99 | print("Processing: \(path)")
100 |
101 | var isDir: ObjCBool = false
102 | if fileManager.fileExists(atPath: path, isDirectory: &isDir) {
103 | if isDir.boolValue {
104 | enumeratePath(path)
105 | } else {
106 | updateContentsOfFile(atPath: path)
107 | }
108 | renameItem(atPath: path)
109 | }
110 |
111 | processedPaths.append(path)
112 | }
113 |
114 | private func shouldSkip(_ element: String) -> Bool {
115 | guard
116 | !element.hasPrefix("."),
117 | !element.contains(".DS_Store"),
118 | !element.contains("Carthage"),
119 | !element.contains("Pods"),
120 | !element.contains("fastlane"),
121 | !element.contains("build")
122 | else { return true }
123 |
124 | let fileExtension = URL(fileURLWithPath: element).pathExtension
125 | switch fileExtension {
126 | case "appiconset", "json", "png", "xcuserstate":
127 | return true
128 | default:
129 | return false
130 | }
131 | }
132 |
133 | private func updateContentsOfFile(atPath path: String) {
134 | do {
135 | let oldContent = try String(contentsOfFile: path, encoding: .utf8)
136 | if oldContent.contains(oldName) {
137 | var newContent = oldContent.replacingOccurrences(of: oldName, with: newName)
138 | if oldContent.contains("\(oldName)Tests") || oldContent.contains("\(oldName)UITests") {
139 | let testClassOldName = oldName.replacingOccurrences(of: "-", with: "_")
140 | newContent = newContent.replacingOccurrences(of: testClassOldName, with: newName)
141 | }
142 | try newContent.write(toFile: path, atomically: true, encoding: .utf8)
143 | }
144 | } catch {
145 | print("Error updating file: \(error.localizedDescription)")
146 | }
147 | }
148 |
149 | private func renameItem(atPath path: String) {
150 | do {
151 | let oldItemName = URL(fileURLWithPath: path).lastPathComponent
152 | if oldItemName.contains(oldName) {
153 | let newItemName = oldItemName.replacingOccurrences(of: oldName, with: newName)
154 | let directoryURL = URL(fileURLWithPath: path).deletingLastPathComponent()
155 | let newPath = directoryURL.appendingPathComponent(newItemName).path
156 | try fileManager.moveItem(atPath: path, toPath: newPath)
157 | print("-- Renamed: \(oldItemName) -> \(newItemName)")
158 | }
159 | } catch {
160 | print("Error renaming file: \(error.localizedDescription)")
161 | }
162 | }
163 | }
164 |
165 | let arguments = CommandLine.arguments
166 | if arguments.count == 3 {
167 | let oldName = arguments[1]
168 | let newName = arguments[2].replacingOccurrences(of: " ", with: "")
169 | let renamer = Renamer(oldName: oldName, newName: newName)
170 | renamer.run()
171 | } else {
172 | print("Invalid number of arguments! Expected OLD and NEW project name.")
173 | }
174 |
--------------------------------------------------------------------------------
/Templates/AppSeedScene.xctemplate/TemplateIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devno39/AppSeed/4a6584a4f051b2b4e8238485788fb059b5b8acab/Templates/AppSeedScene.xctemplate/TemplateIcon.png
--------------------------------------------------------------------------------
/Templates/AppSeedScene.xctemplate/TemplateIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devno39/AppSeed/4a6584a4f051b2b4e8238485788fb059b5b8acab/Templates/AppSeedScene.xctemplate/TemplateIcon@2x.png
--------------------------------------------------------------------------------
/Templates/AppSeedScene.xctemplate/TemplateInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Name
6 | AppSeed Scene
7 | Kind
8 | Xcode.IDEKit.TextSubstitutionFileTemplateKind
9 | Description
10 | Template for creating a new ViewController, ViewModel, Router, and Builder
11 | Summary
12 | Creates ViewController, ViewModel, Router, and Builder
13 | Platforms
14 |
15 | com.apple.platform.iphoneos
16 | com.apple.platform.macosx
17 | com.apple.platform.watchos
18 | com.apple.platform.appletvos
19 |
20 | Options
21 |
22 |
23 | Identifier
24 | name
25 | Name
26 | Scene Name
27 | Type
28 | text
29 | Default
30 | MyScene
31 |
32 |
33 | RequiredOptions
34 |
35 | name
36 |
37 | Nodes
38 |
39 |
40 | Group
41 | ViewController
42 | Path
43 | ___VARIABLE_name___ViewController.swift
44 |
45 |
46 | Group
47 | ViewModel
48 | Path
49 | ___VARIABLE_name___ViewModel.swift
50 |
51 |
52 | Group
53 | Router
54 | Path
55 | ___VARIABLE_name___Router.swift
56 |
57 |
58 | Group
59 | Builder
60 | Path
61 | ___VARIABLE_name___Builder.swift
62 |
63 |
64 | Version
65 | 1.0
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Templates/AppSeedScene.xctemplate/___VARIABLE_name___Builder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BuilderTemplate.swift
3 | // AppSeed
4 | //
5 | // Created by Tunay Alver on 17.11.2024.
6 | //
7 |
8 | import UIKit
9 |
10 | class ___VARIABLE_name___Builder: BaseBuilder {
11 | func build() -> UIViewController {
12 | let router = ___VARIABLE_name___Router()
13 | let viewModel = ___VARIABLE_name___ViewModel()
14 | let viewController = ___VARIABLE_name___ViewController(viewModel: viewModel, router: router)
15 |
16 | return viewController
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Templates/AppSeedScene.xctemplate/___VARIABLE_name___Router.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouterTemplate.swift
3 | // AppSeed
4 | //
5 | // Created by Tunay Alver on 17.11.2024.
6 | //
7 |
8 | import UIKit
9 |
10 | // MARK: - Route Protocol
11 | protocol ___VARIABLE_name___Route {
12 | func push___VARIABLE_name___()
13 | }
14 |
15 | extension ___VARIABLE_name___Route where Self: BaseRouterProtocol {
16 | func push___VARIABLE_name___() {
17 | let vc = ___VARIABLE_name___Builder().build()
18 | viewController?.navigationController?.pushViewController(vc, animated: true)
19 | }
20 | }
21 |
22 | // MARK: - Router
23 | final class ___VARIABLE_name___Router: BaseRouter { }
24 |
--------------------------------------------------------------------------------
/Templates/AppSeedScene.xctemplate/___VARIABLE_name___ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewControllerTemplate.swift
3 | // AppSeed
4 | //
5 | // Created by Tunay Alver on 17.11.2024.
6 | //
7 |
8 | import UIKit
9 | import SnapKit
10 |
11 | final class ___VARIABLE_name___ViewController: BaseViewController<___VARIABLE_name___ViewModel, ___VARIABLE_name___Router> {
12 | // MARK: - Life Cycle
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | }
16 |
17 | // MARK: - Prepare
18 | override func prepare() {
19 | super.prepare()
20 | draw()
21 | }
22 |
23 | // MARK: - Bind
24 | override func bindViewModel() {
25 | super.bindViewModel()
26 | }
27 | }
28 |
29 | // MARK: - Draw
30 | private extension ___VARIABLE_name___ViewController {
31 | private func draw() {}
32 | }
33 |
--------------------------------------------------------------------------------
/Templates/AppSeedScene.xctemplate/___VARIABLE_name___ViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewModelTemplate.swift
3 | // AppSeed
4 | //
5 | // Created by Tunay Alver on 17.11.2024.
6 | //
7 |
8 | import Foundation
9 |
10 | // MARK: - Source
11 | protocol ___VARIABLE_name___ViewModelDataSource { }
12 |
13 | // MARK: - Closure
14 | protocol ___VARIABLE_name___ViewModelClosureSource { }
15 |
16 | // MARK: - Function
17 | protocol ___VARIABLE_name___ViewModelFunctionSource { }
18 |
19 | // MARK: - Protocol
20 | protocol ___VARIABLE_name___ViewModelProtocol: BaseViewModel, ___VARIABLE_name___ViewModelDataSource, ___VARIABLE_name___ViewModelClosureSource, ___VARIABLE_name___ViewModelFunctionSource { }
21 |
22 | // MARK: - ViewModel
23 | final class ___VARIABLE_name___ViewModel: BaseViewModel, ___VARIABLE_name___ViewModelProtocol {
24 | // MARK: - Source
25 |
26 | // MARK: - Closure
27 |
28 | // MARK: - Function
29 | }
30 |
--------------------------------------------------------------------------------
/Templates/install.swift:
--------------------------------------------------------------------------------
1 | // Run with "swift install.swift" command
2 | import Foundation
3 |
4 | let destinationFolder = "Library/Developer/Xcode/Templates/File Templates/Source"
5 | let homeDirectoryURL = FileManager.default.homeDirectoryForCurrentUser
6 | let destinationFolderURL = homeDirectoryURL.appendingPathComponent(destinationFolder)
7 |
8 | func install() {
9 |
10 | let fileManager = FileManager.default
11 | let currentPath = fileManager.currentDirectoryPath
12 |
13 | do {
14 | let files = try fileManager.contentsOfDirectory(atPath: currentPath)
15 | for file in files {
16 | if file == "install.swift" || file == ".DS_Store" {
17 | continue
18 | }
19 | let template = file
20 | let templateURL = URL(fileURLWithPath: template)
21 | let destinationFileURL = destinationFolderURL.appendingPathComponent(template)
22 |
23 | if FileManager.default.fileExists(atPath: destinationFileURL.path) {
24 | try FileManager.default.removeItem(at: destinationFileURL)
25 | try FileManager.default.copyItem(at: templateURL, to: destinationFileURL)
26 | print("✅ Template already exists. So has been replaced successfully 🎉.")
27 | } else {
28 | if FileManager.default.fileExists(atPath: destinationFolderURL.path) == false {
29 | try FileManager.default.createDirectory(at: destinationFolderURL, withIntermediateDirectories: true, attributes: nil)
30 | }
31 | try FileManager.default.copyItem(at: templateURL, to: destinationFileURL)
32 | print("✅ Template installed successfully 🎉.")
33 | }
34 | }
35 | } catch {
36 | print("❌ Ooops! Something went wrong.")
37 | }
38 | }
39 |
40 | install()
41 |
--------------------------------------------------------------------------------
/txts/privacy_policy_dreamcatcher.txt:
--------------------------------------------------------------------------------
1 | Privacy Policy for Dreamcatcher
2 | Gizlilik Politikası - Dreamcatcher
3 |
4 | Effective Date: May 11, 2025
5 | Yürürlük Tarihi: 11 Mayıs 2025
6 |
7 | Dreamcatcher ("we", "us", or "our") respects your privacy.
8 | Dreamcatcher ("biz") gizliliğinize saygı duyar.
9 |
10 | - We do not collect personal information unless explicitly provided.
11 | - Kişisel bilgilerinizi açıkça vermediğiniz sürece toplamıyoruz.
12 |
13 | - We may collect anonymized usage data for improving user experience.
14 | - Kullanıcı deneyimini geliştirmek için anonim kullanım verileri toplayabiliriz.
15 |
16 | By using Dreamcatcher, you agree to this Privacy Policy.
17 | Dreamcatcher uygulamasını kullanarak bu gizlilik politikasını kabul etmiş oluyorsunuz.
--------------------------------------------------------------------------------
/txts/terms_of_use_dreamcatcher.txt:
--------------------------------------------------------------------------------
1 | Terms of Use for Dreamcatcher
2 | Kullanım Şartları - Dreamcatcher
3 |
4 | Effective Date: May 11, 2025
5 | Yürürlük Tarihi: 11 Mayıs 2025
6 |
7 | By using Dreamcatcher, you agree to the following terms:
8 | Dreamcatcher uygulamasını kullanarak aşağıdaki şartları kabul etmiş oluyorsunuz:
9 |
10 | - Subscription renews automatically unless canceled 24 hours before the period ends.
11 | - Abonelik süresi bitmeden 24 saat önce iptal edilmediği sürece abonelik otomatik olarak yenilenir.
12 |
13 | - Prices and terms may change with prior notice.
14 | - Fiyatlar ve şartlar önceden bildirilerek değiştirilebilir.
15 |
16 | If you do not agree to these terms, do not use the App.
17 | Bu şartları kabul etmiyorsanız uygulamayı kullanmayınız.
--------------------------------------------------------------------------------