Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

FlutterでUnixTimeをDateTimeに変換する

Firebaseのライブラリが国際化対応しているため、日時をUnixtimeで持っていた。 それをDartでDateTimeに変換するときのコードで、癖があったのでメモ。

www.kindacode.com

 final timestamp1 = 1627510285; // timestamp in seconds
 final DateTime date1 = DateTime.fromMillisecondsSinceEpoch(timestamp1 * 1000);

fromMillisecondsSinceEpoch はミリ秒を期待しているが、unixtimeが秒までの時間しか持っていないので、1000倍しないとミリ秒が計算されず復元できないというだけの話。

'Timestamp isn't a type' により、flutter buildが通らない

Firestoreのタイムスタンプ型をDartのDateTimeに変換する時に、1時間ほどハマってしまったので。

freezedを使っている人は多いと思いますが、DateTime⇔Timestampを変換するには、以下のようなコンバーターを噛ます必要があります。

class TimestampConverter implements JsonConverter<DateTime, Timestamp> {
  const TimestampConverter();

  @override
  DateTime fromJson(Timestamp json) => json.toDate();

  @override
  Timestamp toJson(DateTime object) => Timestamp.fromDate(object);
}

flutter run しようとすると、「Timestamp isn't a type」でコケてしまい、Dartのエラーが出ました。型を解決できないって話らしい。xxx.g.dartでおなじみ、json_serializableが自動生成したコードで、それが出た。

結論から言えば、xxx.g.dartの元のクラスで、cloud_firestore.dartをインポートする必要があった。

import 'package:cloud_firestore/cloud_firestore.dart'; //これがないと型解決できない

part 'hoge.freezed.dart';
part 'hoge.g.dart';

@freezed
class Hoge with _$Hoge {
  const factory Hoge({
    @TimestampConverter() required DateTime joined,
  }) = _Hoge;
  factory Hoge.fromJson(Map<String, dynamic> json) => _$HogeFromJson(json);
}

part で分割されたコードにおいて、解決できない型があっても、Dartコンパイルエラーにならなかった。そういうもんなのかな。dart:core にない型なので参照が必要なのはそれはそう、って感じ。

PythonでJSONを任意の型にデコードしたい

How to convert JSON data into a Python object? - Stack Overflow

一番簡単なコードがこれ。

import json
j = json.loads(your_json)
u = User(**j)

こういうモデルを定義して、以下のようなコードを書いてFastAPIに食わせたら、普通に動いた。

from typing import List, Optional

from pydantic import BaseModel

class Item(BaseModel):
    item_id: int
    item_name: str
    thumbnail: str
    description: str
    x_list: Optional[List[str]]
    maker: Optional[Maker]

class Maker(BaseModel):
    uuid: str
    name: str
    furigana: str
    email: str
    zipcode: str
    address: str
    building: str
    tel: str
    fax: str
# fastapi
@router.get("/api/item")
async def fetch_item():
    import os
    base = os.path.dirname(os.path.abspath(__file__))
    with open(f'{base}/json/sample.json') as f:
        df = json.load(f)
        result = [Item(**x) for x in df] #これでオブジェクトに型変換できる
    return result

Next.js のgetStaticPropsのチュートリアルをTypeScriptで

nextjs.org

以下の所をTypeScriptで書くとこうなったので、共有。

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// This function gets called at build time
export async function getStaticProps() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

export default Blog

gist.github.com

Visual Studio 2022 17.2系 on ARM Windowsで、IDE固有のバグを2つ踏んだ模様

IDE起因のバグが2つもある。

  • Unrecoverable build error - 0x800700C1
  • テストが実行されない
    • 1週間前動いていたものが、テストが検出されなくなった。

Intel CPUのWindowsでは、最新版(17.2.3)のVS Communityにおいて、上記問題は発生せず。ARMの(M1Pro のParallels) においてのみ。

致命的な問題で、Visual Studio 2022 の Communityはロールバックができない。バージョンを指定して入れ直すことができなくて、有償のエディションだけらしい。なんでよ... JetBrainのToolBox的な機能があれば、本件はすぐ解決するのに。

docs.microsoft.com

Visual Studio 2022 Pro の17.1.7 を落として見た所、上記2つの不具合は起こらなかった。17.2 系固有の問題だった。IDEの不具合を踏むのは辛い所だ。

Visual Studio 2022 17.3 Preview 2 リリースで、Arm64 のWindows11がサポートを予定しているようだ。現在は、17.3.1.1 。7月頃かな。頼むぞ。

.NET Framework 4.8 → .NET 6 へ移行作業にトライ

死ぬほど重い腰を上げて、こちらにトライしてみた。そうはいっても、やることは単純だった。下記のUpgrade Assistantに沿って、Enterを叩きまくる簡単なお仕事。Enterを押す回数が多く、20回ぐらい押した。

dotnet.microsoft.com

やってみた所、あっさり.net6でビルドが出来た。PrintDocumentみたいに、Windows固有のAPIを書くと警告が出るようになった。 [SupportedOSPlatform("windows")]をつけまくるのは辛いので、Windowsしかサポートしないですっていうビルド設定みたいなやつが欲しい。

docs.microsoft.com

唯一困った点が、.NET FrameworkでしかサポートされていないPDFiumViewer が動かない。Unable to load DLL pdfium.dll というエラーが出る。.NET Frameworkでビルドした時はこのエラーが出なかったので、.NET6固有の問題のように思う。

PDFをダイレクト印刷したいがためにこれを使っている(それ以外の用途はない)が、PDFがインストールされているマシンなら、プロセスを起動して印刷できるっぽい。

stackoverflow.com

あっさり以下のコード出てきたけど、acrobat32.exe を直で叩いているためか、Acrobat Readerが立ち上がってしまう。また、このやり方はPDFを開くデフォルトアプリケーションがAdobe Readerでないとだめっぽい。Edgeがデフォルトの場合、PrintToオプションがなさそう。

 string dir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); //これはいらんかも
                Process p = new Process();
                p.StartInfo = new ProcessStartInfo()
                {
                    Arguments = "\"" + printer+ "\"",
                    Verb = "PrintTo",
                    FileName = path, //put the correct path here
                    WorkingDirectory = dir,
                    WindowStyle = ProcessWindowStyle.Hidden
                };
                p.Start();
                p.WaitForExit(1500);

なんて思ってたら、RawPrintなるものがあった!

www.nuget.org

Parallelsの仮想プリンタは印刷できず、Windowsの仮想PDFプリンタは印刷が実行された。なんだろう。コードすげー少ない。とりまfork。実機のプリンタで印刷できれば、なんでもええわ。

10年前に印刷要件の関係でWPFを選んだけど、全部Reactで焼き直したい気持ちが極めて強い... 1年ぐらいかけてまったりと。PDFのダイレクト印刷がReactでできれば、複合機・ドットインパクトプリンタはあまり変わらないはず? ページサイズの設定などが出来ないとやっぱWPFじゃんになるかもですが。

数値をバインドしてるTextBoxの入力値が空になるとエラーになる

現象の説明はこちらに詳しい。

Decimal? とかでnull許容型にしているデータをTextBoxへバインドすると、入力値を消して空にしたときに、赤枠でエラーが出る。何か入力したあとにバックスペースで空文字にすると、空文字として扱われてしまうため、NULLに変換できないためにそのようなことが起こる。 tawamuredays.blog.fc2.com

上記の記事ではConveter作っていたけど、実はBindingにそのようなためのプロパティがある。TargetNullValueだ。 blog.okazuki.jp

<TextBox Text="{Binding Path=NumberInput, UpdateSourceTrigger=PropertyChanged, TargetNullValue=''}" />

これで空文字のときはnullと同等の扱いとなる。めでたしめでたし。