相手に強制的にお願いできるアプリを作った

## はじめに
こんにちは！
[そると](https://twitter.com/jsalt_0525)と申します。

普段は某IT企業でオープン系のシステム開発を行っていますが、個人で仕事で使っていない技術の習得のためにアプリ開発を行っております。

今まで何個かアプリを作りましたが、今回はその中でもちょっと力を入れたアプリの機能紹介、個人的にこだわった点、作ってみて感じたことを記事にしました。

## どんなアプリ？
簡単に言えば「**タスクを相手に送る**」アプリです！

相手にして欲しいこと、お願い、メモなどなど相手に伝えたいことを**指定した時間**に相手に通知させることが出来ます。
※もちろんToDoアプリとして自分のタスクを登録することも出来ます。
![iPhone X-XS-11 Pro – 19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181865/a4f4a9c9-c116-4477-0e6f-28c3a402ed85.png)


## フレームワーク等
* ionic
* capacitor
* Firebase


## 機能紹介
### ①ユーザー登録・ログイン
このアプリでは、タスクを送信し合うために**ユーザー登録**をする必要がありました。
ユーザー登録といえばメールアドレス・パスワードなどを登録するのが一般的だと思いますが、それがめんどくさくてアプリを食わず嫌いされるのは嫌だなと思い、**ユーザー名だけ**でアプリを始められるようにしました。

具体的にはFirebaseの匿名認証を使用しております。

```typescript
firebase.auth().signInAnonymously();
```
![グループ 765.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181865/45e58d09-171b-bb75-3ec1-98fdf12bd17c.png)

### ②やること
サインイン・サインアップ後に最初に表示されるユーザーが登録した**やること**（タスク）を一覧で表示してくれる画面です。
友達になったユーザーから送られてきたタスクは誰から送られてきたかをリストの右側に表示しています。
また、実行したタスクはチェックを付けることが出来ます。
![グループ 768.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181865/5e2c20dd-6c85-b559-774d-7a1fd23f8e4a.png)

### ③友達追加
ユーザー同士が**友達**となってタスクを送信し合えるようになるためにQRコードを使って友達を追加できるようにしました。
※どちらか一方が友達に追加するともう一方の人にも自動的に追加されるようになっております。（Facebookみたいな？）
>※前回[イン○タみたいなQRコード共有の記事](https://qiita.com/beniho/items/3fefaa06d36b58e23a3f)を投稿しましたが、その方法を知る前に作ったアプリだったのでこんなにダサいQRコードになっています・・・
しかも共有できないし・・・😂
次バージョンでの機能UP対象ですね。

![グループ 766.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181865/fe5379b1-f3ab-3015-b19b-7545a8dbf873.png)

#### 主な使用技術
* **[ngx-kjua](https://github.com/werthdavid/ngx-kjua)**
QRコードの表示に使用しました。

* **[dom-to-image](https://github.com/tsayen/dom-to-image)** & **[Photo Library](https://github.com/terikon/cordova-plugin-photo-library)**
保存ボタン押下でQRコードをフォトライブラリに保存するために使用しました。
DOMをPNGに変換した後にフォトライブラリに保存しています。

```DOM→PNG変換してフォトライブラリに保存例.ts
import domtoimage from 'dom-to-image-more';
import { PhotoLibrary } from '@ionic-native/photo-library/ngx';
import { ToastController } from '@ionic/angular';

export class MyQRCodeComponent implements OnInit {

  constructor(private photoLibrary: PhotoLibrary, 
              private toastController: ToastController) {
  }

  saveQR() {
    //QRコード取得
    const div = document.getElementById('container');
    //DOM→PNG変換してフォトライブラリに保存
    domtoimage.toPng(div).then((dataUrl) => {
      this.photoLibrary.requestAuthorization({
        "read": true,
        "write": true
      }).then(() => {
        this.photoLibrary.saveImage(dataUrl,'たのんだー').then(()=>{
          this.showToast("保存しました")
        }).catch((err) => {
          console.log(err);
          this.showToast("保存出来ませんでした")
        });
      }).catch((err) => {
        console.log(err);
        this.showToast("保存出来ませんでした")
      });
    });
  }

  async showToast(message) {
    const toast = await this.toastController.create({
      message: message,
      duration: 2000,
      color: "dark"
    });
    toast.present();
  }
}
```

### ④タスク作成・送信
タスクは**自分用**と**友達用**の両方作成できるような画面にしました。
また、**一回のみ**・**毎日**・**毎週**・**毎月**の４パターンで通知を任意で設定できるようにしました。

![グループ 767.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181865/2c5846d5-2736-729f-a4ba-8a1e54b1b35a.png)

#### 主な使用技術
* **[Local Notifications](https://github.com/katzer/cordova-plugin-local-notifications)**  
通知の登録用に使いました。  
自分用のタスクはタスク追加時に通知の登録を行い、送られてきたタスクは受信時に通知の登録を行っております。

```通知登録例.ts
import { LocalNotifications } from '@ionic-native/local-notifications/ngx';

export class MakeTaskPage implements OnInit {

  //やることデータ
  data: { title: string, memo: string, date: string, time: string, week: string } = { title: '', memo: '', date: '', time: '', week: '' };

  //通知種類
  notiKind: string = ""

  constructor(private localNotifications: LocalNotifications) {}

  //やること作成
  makeTask() {

    //******************* ~ なんやかんややること作成処理 ~ *******************//

    //通知ID取得処理
    const ID: string = this.getID();

    const choiceDate = new Date(this.data.date);
    const year: number = choiceDate.getFullYear();
    const month: number = choiceDate.getMonth();
    const dayOfWeek: number = choiceDate.getDay();
    const day: number = choiceDate.getDate();
    const choiceTime = new Date(this.data.time);
    const hour: number = choiceTime.getHours();
    const minute: number = choiceTime.getMinutes();

    switch (this.notiKind) {
    case "毎日":
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { every: { hour: hour, minute: minute } },
      });
      break;

    case "毎週":
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { every: { weekday: dayOfWeek, hour: hour, minute: minute } },
      });
      break;

    case "毎月":
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { every: { day: day, hour: hour, minute: minute } },
      });
      break;

    default:
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { at: new Date(year, month, day, hour, minute) },
      });
      break;
    }
  }
}
```

### ⑤その他機能
直近１週間のタスク送受信履歴やアカウント設定なども行えます。
![グループ 769.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181865/4ad39577-a677-0488-6c41-4ba4013af66a.png)

## こだわったところ
自分がこのアプリでこだわった部分についてご紹介します。
尚、こだわり前のUIは以下のような感じでした。
![グループ 770.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181865/56cfb35b-0a68-ab11-474a-3644ee1e42be.png)

### UI・フォント
UIは見やすさを重視して、背景とツールバー、タブバーを同一色にし、差し色で青を使うようにしました。これによって**意味があるものがパッと見ですぐわかる**ということとなんとなく**デザインが締まって見える**ようになりました。
また、フォントは読みやすくて今っぽい丸めなフォントを探していました。ただ、実際あんまり丸過ぎると可愛くなってしまってユーザーを選んでしまう恐れがあったので絶妙な感じの[Mgen+ (ムゲンプラス)](http://jikasei.me/font/mgenplus/)にしました。

### 難しくし過ぎない
最初は通知する時間をもっと細かい設定が出来るようにしていたのですが、利用者のことを考えると**ある程度機能が制限されていても操作しやすい**画面の方がいいのかなと思ったので４パターンで設定出来るようにしました。
また、アプリ名も上記にある通り、「Sentifer」という名前を仮で付けていたのですが、Sentiferっていう文字を見ても**何ができるアプリなのかわかりづらい**と思いましたので、「たのんだー」に変更しました。

### プライバシー
友達をIDで検索する機能を付けようか考えましたが、**自分のIDが流出して知らない人からたくさんタスクが届いても嫌だよなあ**と思い、知っている人だけにQRを渡して知り合い同士で使っていただけるような仕組みにしました。また、画像は載せていませんが、友達を**ブロック（受信拒否）**する機能や**通報**できる機能なども実装しております。

## まとめ
もっと簡単にすぐ完成すると思っていましたが、いろいろ考えながら作ると**意外と時間がかかる**ということを感じました。あとは、個人開発は本当にモチベーションでその日の作業時間が決まってしまうのでずーっと**高いモチベーションを維持するのが大変**でした。でもなんだかんだありましたが1つの物として完成させることが出来たことは**良い経験**になりましたし、**達成感**がありました。

### アプリのリンク
[iOS](https://apps.apple.com/jp/app/%E3%81%9F%E3%81%AE%E3%82%93%E3%81%A0%E3%83%BC/id1500995068)
[android](https://play.google.com/store/apps/details?id=jp.JShiota.Sentifer)