Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions src/routes/docs/tutorials/apple/step-1/+page.markdoc
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
---
layout: tutorial
title: Coming soon
title: Build an habit tracker with SwiftUI
description: Learn to build an Apple app with no backend code using an Appwrite backend.
framework: Apple
category: Mobile and native
step: 1
draft: true
back: /docs
---

Improve the docs, add this guide.
**Habit tracker**: an app to keep track of your habit.
In this tutorial, you will build Habit tracker with Appwrite and SwiftUI.

We still don't have this guide in place, but we do have some great news.
The Appwrite docs, just like Appwrite, is completely open sourced.
This means, anyone can help improve them and add new guides and tutorials.
{% only_dark %}
![Habit Tracker Screenshot](/images/docs/tutorials/dark/apple-habit-tracker.png)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please give me originals of all your screenshots taking in a 1400x900 view port using DPR:3.0 on your browser's developer tools.

We will have our design team edit the screenshots to fit our style.

Copy link
Contributor

Choose a reason for hiding this comment

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

@Mujhtech please provide original images for all screenshots.

Copy link
Author

Choose a reason for hiding this comment

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

Copy link
Author

Choose a reason for hiding this comment

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

Those are the screenshots @gewenyu99

{% /only_dark %}
{% only_light %}
![Habit Tracker Screenshot](/images/docs/tutorials/apple-habit-tracker.png)
{% /only_light %}

If you see this page, **we're actively looking for contributions to this page**.
Follow our contribution guidelines, open a PR to [our Website repo](https://github.com/appwrite/website), and collaborate with our core team to improve this page.
# Concepts {% #concepts %}

This tutorial will introduce the following concepts:

1. Setting up your first project
2. Authentication
3. Databases and collections
4. Queries and pagination


# Prerequisites {% #prerequisites %}

1. Basic knowledge of Swift and SwiftUI.
2. Have [Xcode](https://developer.apple.com/download/all/?q=Xcode) installed on your computer.
23 changes: 23 additions & 0 deletions src/routes/docs/tutorials/apple/step-2/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
layout: tutorial
title: Create app
description: Create and app with Appwrite Cloud and Xcode.
step: 2
---

# Setup new project {% #new-project %}

Open Xcode and select **Create new project**, then select app as template for iOS and click **Next**. Fill out all of the required information, such as Product Name, Organization identifier, Interface (SwiftUI), and click **Next**. Select the folder where you want to set up the project and click **Create**.

![Create project screen](/images/docs/tutorials/xcode-new-project-setup.png)

# Add the Appwrite SDK {% #appwrite-sdk %}
To add the Appwrite SDK for Apple as a dependency, open the **File** menu and click **Add Package Dependencies**.

In the **Package URL** search box, enter `https://github.com/appwrite/sdk-for-apple`.

Once the SDK is found, select **Up to Next Major Version** as your **Dependency Rule** and click **Add Package**.

When dependency resolution is complete, click **Add Package** again to add the SDK package to your target.

![Create project screen](/images/docs/tutorials/xcode-add-appwrite-sdk.png)
75 changes: 75 additions & 0 deletions src/routes/docs/tutorials/apple/step-3/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
layout: tutorial
title: Set up Appwrite
description: Import and configure a project with Appwrite Cloud and Xcode.
step: 3
---

# Create project {% #create-project %}

Head to the [Appwrite Console](https://cloud.appwrite.io/console).

{% only_dark %}
![Create project screen](/images/docs/quick-starts/dark/create-project.png)
{% /only_dark %}
{% only_light %}
![Create project screen](/images/docs/quick-starts/create-project.png)
{% /only_light %}

If this is your first time using Appwrite, create an account and create your first project.

Then, under **Add a platform**, add an **Apple app**. Choose any of **iOS**, **macOS**, **watchOS** or **tvOS** as your Apple platform. If you are creating a multi-platform app, you can add more platforms later.

Add your app's **product name** and **bundle identifier**, your bundle identifier is the one entered when creating an Xcode project. For existing projects, you should use the **bundle identifier** from your project files **Identity** section.

{% only_dark %}
![Add a platform](/images/docs/quick-starts/dark/add-platform.png)
{% /only_dark %}
{% only_light %}
![Add a platform](/images/docs/quick-starts/add-platform.png)
{% /only_light %}

# Setup Database {% #setup-database %}

In Appwrite, data is stored as a collection of documents. Create a collection in the [Appwrite Console](https://cloud.appwrite.io/) to store our habits.

# Create database {% #create-database %}

Head to your [Appwrite Console](https://cloud.appwrite.io/console/) and create a database and name it `Habit-SwiftUI`.
Optionally, add a custom database ID.

# Create collection {% #create-collection %}
Create a collection and name it `habits`. Optionally, add a custom collection ID.

Navigate to **Attributes** and create attributes by clicking **Create attribute** and add the following attributes.

| Field | Type | Required | Size | Min | Max | Default Value |
|----------------|----------|----------|------|-----|-----|---------------|
| userId | String | Yes | 250 | | | |
| title | String | Yes | 250 | | | |
| description | String | No | | | | |
| icon | String | No | 200 | | | calendar |
| goals | Integer | Yes | | 1 | 10 | 1 |
| goalCompleted | Integer | Yes | | 0 | 10 | 0 |
| startDate | DateTime | No | | | | |
| endDate | DateTime | No | | | | |

Attributes define the structure of your collection's documents. Enter **Attribute key** and **Size**. For example, `title` and `100`.

Navigate to **Settings** > **Permissions** and add a new role **All Users**.
Check the **CREATE**, **UPDATE**, **DELETE** and **READ** permissions, so anyone can create and read documents.

Create a swift file name `Database` in the `Shared/Constant` folder. We will use this file to store the database id and collection id from Appwrite as enum.

```swift
import Foundation

enum Database: String {
case habit = "[DATABASE_ID]"
}


enum DatabaseCollections : String {
case habits = "[COLLECTION_ID]"
}
```
157 changes: 157 additions & 0 deletions src/routes/docs/tutorials/apple/step-4/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
layout: tutorial
title: Manage service and view models
description: Manage Appwrite wervice using Appwrite Apple SDK and SwiftUI application View Model.
step: 4
---

# Appwrite service {% #appwrite-service %}

Create a new file AppwriteService.swift inside `Shared/Services` folder and add the following code to it, replacing [YOUR_PROJECT_ID] with your project ID. The purpose of this file is to initialize Appwrite SDK and create necessary methods needed for both authentication and read/write from documents.
Copy link
Contributor

Choose a reason for hiding this comment

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

I like that clarification was added here 👍🏽


```swift
import Foundation
import Appwrite
import JSONCodable

class AppwriteService {
var client: Client
var account: Account
var database: Databases

public init() {
self.client = Client()
.setEndpoint("https://cloud.appwrite.io/v1")
.setProject("[YOUR_PROJECT_ID]")
self.account = Account(client)
self.database = Databases(client)
}


public func getDocs<T>(_ db: Database, _ collection: DatabaseCollections, queries: [String]? = nil) async throws -> DocumentList<T> {
try await database.listDocuments<T>(
databaseId: db.rawValue,
collectionId: collection.rawValue,
queries: queries,
nestedType: T.self
)
}

public func insertDoc(_ db: Database, _ collection: DatabaseCollections, data: Any) async throws {
_ = try await database.createDocument(
databaseId: db.rawValue,
collectionId: collection.rawValue,
documentId: ID.unique(),
data: data
)
}


public func updateDoc(_ db: Database, _ collection: DatabaseCollections, _ id: String, data: Any) async throws {
_ = try await database.updateDocument(
databaseId: db.rawValue,
collectionId: collection.rawValue,
documentId: id,
data: data
)
}


public func removeDoc(_ db: Database, _ collection: DatabaseCollections, _ id: String, data: Any) async throws {
_ = try await database.deleteDocument(
databaseId: db.rawValue,
collectionId: collection.rawValue,
documentId: id
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Screenshot 2023-10-24 at 6 28 57 PM Is there a chance your using an old XCode/swift version that could cause inconsistencies like this? XCode didn't like your code here :P

Copy link
Author

Choose a reason for hiding this comment

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

I just noticed what likely happened; a step is missing. Sorry about that. I have updated step 3 to include that part

}

}
```

# Snackbar service {% #snackbar-service %}

In order to manage error toast, we need a view model to handle and dispatch error messsgae to our UI. Create a new file SnackbarService.swift inside `Shared/Services` folder and add the following code to it.

```swift
import SwiftUI

struct SnackBarState: Identifiable, Equatable {
static func == (lhs: SnackBarState, rhs: SnackBarState) -> Bool {
lhs.id == rhs.id
}

let id = UUID()
let hasError: Bool
let error: Error
}

class SnackBarService: ObservableObject {
@Published private (set) var snackBarState: SnackBarState?

@MainActor
func displayError(_ error: Error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Very interesting way of showing errors. I definitely have to try this out sometime 😃

snackBarState = nil
snackBarState = SnackBarState(hasError: true, error: error)
DispatchQueue.main.asyncAfter(deadline: .now() + 4.0, execute: {
withAnimation(.easeOut(duration: 0.3)) {
self.snackBarState = nil
}
})
}
}
```

Add the following code to SnackbarView.swift inside `Shared/Views` folder.

```swift
import SwiftUI

struct SnackbarView: View {
@State private var isAnimating: Bool = false
@State var text: String
@State var isError: Bool = true

var body: some View {
HStack {
Text(text)
.foregroundColor(.white)
.lineLimit(1...2)
.multilineTextAlignment(.leading)
.padding()
}
.background(isError ? .red : Color.accentColor)
.cornerRadius(10)
.padding(.top, 15)
.opacity(isAnimating ? 1 : 0)
.offset(y: isAnimating ? -20 : 20)
.onAppear {
withAnimation(.easeOut(duration: 0.3)) {
isAnimating.toggle()
}
}
}
}
```

# Habit model {% #habit-model %}

Add the following code to HabitModel.swift inside `Shared/Models` folder.

```swift
import Appwrite
import Foundation



struct HabitModel: Codable, Identifiable {
let id: String
let userId: String
let title: String
let description: String?
let goals: Int?
let goalCompleted: Int?
let icon: String
let startDate: String?
let endDate: String?
}
```
Loading