この夏をみんなで乗り切ろう！水分補給カウントアプリ爆誕！！【iphone・AppleWatchアプリ】



## 最近暑すぎません？！ ##
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/f7d92aa3-59d4-278e-4196-4f0016fc471f.png" width=70%>

私の地域では連日
熱中症警戒アラートが出ているほど
毎日３０℃を大幅に超える日が続いています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/edeacc0e-5cd4-1b86-1c7f-f34da11f3ca0.png" width=70%>

自宅で過ごしている時も
救急車の音がよく聞こえるようになり
熱中症の患者さんも増えているようです。心配。

## 園児はどこで遊んでる？！ ##

そんな中、先日前職の幼稚園へ
遊びに行く機会がありました。

保育室はエアコンが効いており
涼しかったのですが
廊下や外は空気がモワモワしていて
とても暑かったです。

現在は夏休みに入ったそうですが
７月はずっとエアコンの効いた保育室内で
園児は遊んでいたようです。良かった。
そりゃそうか。でも・・

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/42db0d98-cad4-7dfd-b43b-c4597d66a29c.png" width=70%>

子どもたちの安全を守るために
考えてくれている
保育士さんたちに本当毎日感謝です。

**環境は整っていましたが
次に気をつけることは水分補給です。**

保育士は時間を見ることが多く
腕に時計をつけている方もいます。
時間を見て水分補給のタイミングを見て
保育士が一斉に子どもたちに促しています。
（顔色を見て個別に声かけることも追加であります）

遊んでいて夢中になる子どもたちに
いかに言葉的にも強制的にならず
自主的に飲めるか当時苦労していました。

なので保育現場の改革という意味でも
子どもたちが自主的に水分を
取れるようなものを・・・

**ちなみにiphoneを見る余裕はないので
保育現場にぴったりな
AppleWatchでアプリを開発しました！**

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/aa2db2dc-bb29-03ea-ea3f-94c122bcae00.png" width=70%>

↓動いている様子です（早送りです）

https://x.com/riyu___11/status/1816006427334566238

水分補給の目安に推奨されている１５分を
自動的に繰り返し、子どもたちも
この水分が減っていくのを客観的に見ることができ
自主的に飲みにいくきっかけになったり

月齢によっては
「喉が渇いているのかな？」と
自分が飲むことで
このキャラクターにお水をあげている
感覚になる姿も予測されます♡

**こちらはシュミレーターなので
実際にご自身のxcodeから、作成手順内の
コード入れていただくと使用できます！**


### ↓当時の保育現場での対応も書いています ###

https://zenn.dev/riyu/scraps/b795c5e515024c



## プロダクトを一緒に作ろう！ ##

### 準備するツール ###

💻　**Xcode**：https://developer.apple.com/jp/xcode/

**Macのみ実装可能です！**

[ 特徴 ]

→Appleが提供している統合開発環境（IDE）です。
　iPhoneやiPad、MacなどのApple製端末で
 　使用するアプリを作成できます。

**Swift（スウィフト）**
アップルのiOSおよびMacOS､Linuxで利用出来る
プログラミング言語
→基本的にxcodeを使って開発をする



### 作り方 ###

**⚠️注意**
初めてXcodeをダウンロードする方は
容量も大きく、時間もかかるため
 事前準備に時間を要することを
 覚えておいてもらえると良いです。


①Xcodeでログインし、「Create New Project」から
作成を始めます。(ver.が最新か確認してください)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/10dab136-72fb-1160-fe21-0cd53d514913.png
" width=70%>

②上の「WatchOS」から「App」を押してください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/6436046d-5862-5a27-da71-fde8402df494.png
" width=70%>

 ③プロジェクトを始めるにあたり
 項目の入力が必要になります。

 Product Name：好きな名前を入れる
 （日本語で入れないほうがいいです）
 Team：選択できるので、自分の名前を選ぶ
 Organization Identifier：com.の後に自分の好きな名前入れる

 １番下の選択できるところは
 今回はAppleWatchのみの開発なので
 「Watch-only App」を選びましょう。

 <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/fe58da3d-3b88-0d7b-0fe6-75835ea3721a.png
" width=70%>

④ 左側の「ContentView.swift」を開きます

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3720831/73c196ef-1ee6-28ab-eee8-9ef0d5381bb9.png
" width=70%>

⑤既に書いてあるコードを削除し
　下記のコードを挿入します。

<details><summary>コードはこちら</summary>

```Swift

import SwiftUI
import UserNotifications

struct ContentView: View {
    @State private var timeRemaining = 900 // 15分 = 900秒
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Color.blue.opacity(0.2)
                    .edgesIgnoringSafeArea(.all)

                VStack {
                    Text("いっしょに、のもう")
                        .font(.system(size: geometry.size.width * 0.06))
                        .padding(.top, geometry.size.height * 0.05)

                    Spacer()

                    // キャラクターを表示する
                    WaterCharacterView(timeRemaining: timeRemaining)
                        .frame(width: geometry.size.width * 0.7, height: geometry.size.height * 0.6)

                    Spacer()

                    // 時間の表示
                    Text(timeString(time: timeRemaining))
                        .font(.system(size: geometry.size.width * 0.08, weight: .bold))
                        .foregroundColor(.white) // テキストカラーを白に設定
                        .padding(.bottom, geometry.size.height * 0.05)
                }
            }
            .onReceive(timer) { _ in
                if timeRemaining > 0 {
                    timeRemaining -= 1
                } else {
                    sendNotification()
                    timeRemaining = 900 // リセットして再スタート
                }
            }
        }
    }

    func timeString(time: Int) -> String {
        let minutes = Int(time) / 60 % 60
        let seconds = Int(time) % 60
        return String(format:"%02i:%02i", minutes, seconds)
    }

    func sendNotification() {
        let content = UNMutableNotificationContent()
        content.title = "水を飲む時間です！"
        content.body = "休憩して水を飲みましょう。"
        content.sound = .default

        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
        UNUserNotificationCenter.current().add(request)
    }
}

struct WaterCharacterView: View {
    let timeRemaining: Int
    let totalTime = 900

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                WaterDropShape(progress: CGFloat(timeRemaining) / CGFloat(totalTime))
                
                CharacterFace()
                    .frame(width: geometry.size.width * 0.6, height: geometry.size.height * 0.3)
                    .position(x: geometry.size.width / 2, y: geometry.size.height * 0.4)

                CharacterLimbs()
                    .frame(width: geometry.size.width, height: geometry.size.height)
            }
            .animation(.easeInOut(duration: 1), value: timeRemaining)
        }
    }
}

struct WaterDropShape: View {
    let progress: CGFloat

    var body: some View {
        Circle()
            .stroke(Color.black, lineWidth: 2)
            .background(
                Circle()
                    .fill(LinearGradient(
                        gradient: Gradient(colors: [Color.blue.opacity(0.7), Color.blue]),
                        startPoint: .top,
                        endPoint: .bottom))
                    .scaleEffect(x: 1, y: progress, anchor: .bottom)
            )
            .clipShape(Circle())
    }
}

struct CharacterFace: View {
    var body: some View {
        VStack {
            HStack {
                Eye()
                Eye()
            }
            Mouth()
        }
    }
}

struct CharacterLimbs: View {
    var body: some View {
        GeometryReader { geometry in
            Group {
                Hand()
                    .rotationEffect(.degrees(-45))
                    .position(x: geometry.size.width * 0.2, y: geometry.size.height * 0.6)
                Hand()
                    .rotationEffect(.degrees(45))
                    .position(x: geometry.size.width * 0.8, y: geometry.size.height * 0.6)
                Foot()
                    .rotationEffect(.degrees(20))
                    .position(x: geometry.size.width * 0.35, y: geometry.size.height * 0.85)
                Foot()
                    .rotationEffect(.degrees(-20))
                    .position(x: geometry.size.width * 0.65, y: geometry.size.height * 0.85)
            }
        }
    }
}

struct Eye: View {
    var body: some View {
        Circle()
            .fill(Color.black)
            .frame(width: 8, height: 8)
            .padding(.horizontal, 4)
    }
}

struct Mouth: View {
    var body: some View {
        Path { path in
            path.move(to: CGPoint(x: 0, y: 0))
            path.addQuadCurve(to: CGPoint(x: 16, y: 0), control: CGPoint(x: 8, y: 8))
        }
        .stroke(Color.black, lineWidth: 1)
        .frame(width: 16, height: 8)
        .offset(y: 4)
    }
}

struct Hand: View {
    var body: some View {
        Capsule()
            .fill(Color.blue)
            .frame(width: 8, height: 24)
    }
}

struct Foot: View {
    var body: some View {
        Capsule()
            .fill(Color.blue)
            .frame(width: 8, height: 16)
    }
}

struct WaterReminderApp_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```
</details>

シュミレーターにでてくるので
１５分が自動的に繰り返し表示されます！


<br>

## 今後はこれもやりたい！！ ##

💡
０分になった瞬間に振動したり
水の涼しい音が鳴るようになると
より楽しめるのでは？？

💡
他にもiphoneでも開発してみたのですが
子どもたちが自主的に見るという点でも
大きな画面（ipadなど）で
常に表示しておくと良いのでは？？

まだまだアップデートできそうな
夏にぴったりのアプリになりそうです！！

**子どもに限らずわたしたち大人の皆さんも
たくさん水分補給していきましょ〜う！！
そしてこの暑い夏を乗り切りましょう！**