[Flutter]Flutterを用いたクソアプリの作り方の一例

![スクリーンショット 2023-11-13 14.51.52（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/27e717eb-abc6-a5fa-1722-b717a0e9b188.png)


こんにちは。いせりゅーです。
この記事は、「クソアプリ Advent Calendar 2023」のアドベントカレンダーになっております。

https://qiita.com/advent-calendar/2023/kuso-app


今回は、Flutterを用いたクソアプリの作り方を簡単に紹介します。Flutterを用いた理由は、僕がFlutterエンジニアだったからです。

# 自己紹介

![スクリーンショット 2023-06-13 7.33.21（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/0fe9ebc3-b7ea-a020-56a2-0f2086968417.png)


# クソアプリの作り方

## その１　サンプルアプリを作ろう

今回は、クソアプリを作るのにフォーカスを当てるために、`flutter create <アプリ名>`で作られるカウントアプリを魔改造しようと思います。



<details><summary><b>main.dart</b></summary>

```dart:main.dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:$_counter',
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

```
</details>

## その２ どうしたらクソアプリになるか考えてみる

個人的なクソアプリの概念ですが、理不尽であることや「なんで？」と思われることがとても大切だと思いました。
そのため、今回は以下のような対応を行いました。

- ちゃんとカウントできないようにする
  - カウントアップするたびに素数をランダムで表示する
  - いっそのこと、数字ではなく適当な文字を表示する
- リセットする方法を隠しボタンにする
- どうでもいい広告を入れてみる
- 変なタップ音をつける


# 実装するよぉぉぉぉ

### 1.ちゃんとカウントできないようにする。
この実装については、インクリメントを削除するだけでできそうですね。

```diff
void _incrementCounter() {
-  setState(() {
-   _counter++;
- });
}

```

↓実際に動かしてみました。

![Simulator Screen Recording - iPhone 15 Pro - 2023-11-17 at 14.04.02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/34b0ded8-8d6e-63ac-50d1-f5ab818d3722.gif)


「You have pushed the button this many times」と書いてあるくせに、ボタンを押しても増えないのは既におかしいですね。



https://github.com/iseruuuuu/facking_counter_app/commit/26a44cb52cb671f68b5aa4a197ead7a240e908c9


### 2.カウントアップするたびに素数のみを表示する

`_incrementCounter()`の記載が何もないのでせっかくだから変な要素を加えてみたいですね。

今回は、ボタンを押すと＋１をするのではなく、数字の結果を素数のみにします。

考え方としては、
<b>１、現在の数値を保持するための変数を定義します。（`int _counter = 0;`）</b>
<b>２、次の素数を見つける関数を実装します。この関数は現在の数値より大きい最小の素数を返すように実装します。</b>

```dart:main.dart
int _counter = 0;

 void _incrementCounter() {
    int nextNumber = _counter + 1;
    while (!isPrime(nextNumber)) {
      nextNumber++;
    }
    setState(() {
      _counter = nextNumber;
    });
  }

  // ２、素数を見つける関数
  bool isPrime(int number) {
    for (int i = 2; i <= number ~/ 2; i++) {
      if (number % i == 0) {
        return false;
      }
    }
    return true;
  }
```

↓実際に動かしてみました。


![Simulator Screen Recording - iPhone 15 Pro - 2023-11-17 at 13.58.23.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/88272cd4-943b-fca6-2a43-a96e87f6cc8f.gif)


これはこれで良さそう・・・？？？
別のアプリで使えそうですね😆


https://github.com/iseruuuuu/facking_counter_app/commit/39a610dfb5d14e9b249f9fd7e483a833a734804c



# 3.いっそのこと、数字ではなく適当な文字を表示する

2番目の実装で素数のみの表示になりましたが、数字ではなく、適当な文字を表示してもいいなと思いました。
実装としては、<b>ランダムな日本語の5文字を並べる</b>ことにしました。


今回は大幅にコードの内容が変わったので、全体のコードを載せます。

<details><summary><b>main.dart</b></summary>

```dart:main.dart
import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _randomString = 'Hello World';

  void _generateRandomString() {
    _randomString = generateRandomString(5);
    setState(() {});
  }

  String generateRandomString(int length) {
    const characters = 'あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん';
    final random = Random();

    // 文字コードを受け取り、それを文字列に変換します
    return String.fromCharCodes(
      // 指定された長さのリストを作成
      Iterable.generate(
        length,
        // リストの各要素（この場合は文字コード）をどのように生成するかを定義
        (_) => characters.codeUnitAt(
          random.nextInt(characters.length),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              _randomString,
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _generateRandomString,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

```
</details>

↓実際に動かしてみました。

![Simulator Screen Recording - iPhone 15 Pro - 2023-11-17 at 14.24.57.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/05cb8483-95ef-b1ce-122a-8772c43248d7.gif)


どんどん謎なアプリになりましたね。

https://github.com/iseruuuuu/facking_counter_app/commit/f936c092b8e0354dfd8d0edd7d54d5797250ae19


今回はここまで。

# 感想
この後ももっとクソアプリ化してもいいかなと思いましたが、長くなりそうなので今回はここまでです。
もし、好評でしたら作成します😆（いいねやコメント待っています！！）

リポジトリはこちらです。

https://github.com/iseruuuuu/facking_counter_app




# 最後に
少し宣伝をさせてください！！

株式会社ゆめみの23卒のメンバーでアドベントカレンダーを作成しています。
新卒のフレッシュな記事がたくさん投稿予定なので、少しでも興味があれば購読いただけると幸いです！！

https://qiita.com/advent-calendar/2023/yumemi-23-graduation