Min Time 2.0.3 - redistribution notices Original developer: Thomas Künneth Source: https://codeberg.org/tkuenneth/mintime Project license declared by F-Droid: MIT Corresponding source: min-time-2.0.3-source.tar.gz APK redistributed without modification. Store media is normalized without cropping. FILE: com.thomaskuenneth.mintime_67_src.tar.gz/LICENSE MIT License Copyright (c) 2015 - 2024 Thomas Künneth Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. FILE: com.thomaskuenneth.mintime_67_src.tar.gz/app/src/main/java/com/thomaskuenneth/mintime/LicenseNames.java /* * MIT License * * Copyright (c) 2026 Thomas Künneth * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.thomaskuenneth.mintime; import android.content.Context; import androidx.annotation.NonNull; final class LicenseNames { private LicenseNames() { } @NonNull static String fromUrl(@NonNull Context context, @NonNull String licenseUrl) { String url = licenseUrl.strip().toLowerCase(); if (isApache2(url)) { return context.getString(R.string.license_apache_2_0); } if (isApache1_1(url)) { return context.getString(R.string.license_apache_1_1); } if (isEupl1_2(url)) { return context.getString(R.string.license_eupl_1_2); } if (isEupl1_1(url)) { return context.getString(R.string.license_eupl_1_1); } if (isLgplGpl3(url)) { return context.getString(R.string.license_lgpl_gpl_3_0); } if (isGplClasspathException(url)) { return context.getString(R.string.license_gpl_2_0_classpath_exception); } if (isAgpl3(url)) { return context.getString(R.string.license_agpl_3_0); } if (isGpl3(url)) { return context.getString(R.string.license_gpl_3_0); } if (isGpl2(url)) { return context.getString(R.string.license_gpl_2_0); } if (isLgpl3(url)) { return context.getString(R.string.license_lgpl_3_0); } if (isLgpl2_1(url)) { return context.getString(R.string.license_lgpl_2_1); } if (isMpl2(url)) { return context.getString(R.string.license_mpl_2_0); } if (isMpl1_1(url)) { return context.getString(R.string.license_mpl_1_1); } if (isEpl2(url)) { return context.getString(R.string.license_epl_2_0); } if (isEpl1(url)) { return context.getString(R.string.license_epl_1_0); } if (isCddl(url)) { return context.getString(R.string.license_cddl_1_0); } if (isMit(url)) { return context.getString(R.string.license_mit); } if (isBsd3(url)) { return context.getString(R.string.license_bsd_3_clause); } if (isBsd2(url)) { return context.getString(R.string.license_bsd_2_clause); } if (isIsc(url)) { return context.getString(R.string.license_isc); } if (isCc0(url)) { return context.getString(R.string.license_cc0_1_0); } if (isUnlicense(url)) { return context.getString(R.string.license_unlicense); } if (isBsl(url)) { return context.getString(R.string.license_bsl_1_0); } if (isPsf(url)) { return context.getString(R.string.license_psf_2_0); } if (isArtistic2(url)) { return context.getString(R.string.license_artistic_2_0); } return context.getString(R.string.license_other); } private static boolean isApache2(String url) { return url.contains("apache.org/licenses/license-2.0") || url.contains("opensource.org/licenses/apache-2.0") || url.contains("spdx.org/licenses/apache-2.0"); } private static boolean isApache1_1(String url) { return url.contains("apache.org/licenses/license-1.1"); } private static boolean isEupl1_2(String url) { return url.contains("eupl-1.2") || url.contains("eupl/v1.2") || url.contains("licence-eupl-12"); } private static boolean isEupl1_1(String url) { return url.contains("eupl-1.1") || url.contains("eupl/v1.1") || url.contains("europa.eu/legal/eupl") || url.contains("joinup.ec.europa.eu/software/page/eupl"); } private static boolean isLgplGpl3(String url) { return url.contains("gnu.org/licenses/lgpl") && url.contains("gpl-3"); } private static boolean isGplClasspathException(String url) { return url.contains("classpath") && url.contains("gpl"); } private static boolean isAgpl3(String url) { return url.contains("gnu.org/licenses/agpl") || url.contains("agpl-3.0") || url.contains("spdx.org/licenses/agpl-3.0"); } private static boolean isGpl3(String url) { return url.contains("gnu.org/licenses/gpl-3") || url.contains("gpl-3.0") || url.contains("spdx.org/licenses/gpl-3.0"); } private static boolean isGpl2(String url) { return url.contains("gnu.org/licenses/gpl-2") || url.contains("gpl-2.0") || url.contains("spdx.org/licenses/gpl-2.0"); } private static boolean isLgpl3(String url) { return url.contains("gnu.org/licenses/lgpl-3") || url.contains("lgpl-3.0") || url.contains("spdx.org/licenses/lgpl-3.0"); } private static boolean isLgpl2_1(String url) { return url.contains("gnu.org/licenses/lgpl-2.1") || url.contains("lgpl-2.1") || url.contains("spdx.org/licenses/lgpl-2.1"); } private static boolean isMpl2(String url) { return url.contains("mozilla.org/mpl/2") || url.contains("mpl-2.0") || url.contains("spdx.org/licenses/mpl-2.0"); } private static boolean isMpl1_1(String url) { return url.contains("mozilla.org/mpl/1.1") || url.contains("mpl-1.1") || url.contains("spdx.org/licenses/mpl-1.1"); } private static boolean isEpl2(String url) { return url.contains("eclipse.org/legal/epl-2") || url.contains("epl-2.0") || url.contains("spdx.org/licenses/epl-2.0"); } private static boolean isEpl1(String url) { return url.contains("eclipse.org/legal/epl") || url.contains("epl-1.0") || url.contains("opensource.org/licenses/epl-1.0") || url.contains("spdx.org/licenses/epl-1.0"); } private static boolean isCddl(String url) { return url.contains("opensource.org/licenses/cddl") || url.contains("cddl-1.0") || url.contains("spdx.org/licenses/cddl-1.0"); } private static boolean isMit(String url) { return url.contains("opensource.org/licenses/mit") || url.contains("opensource.org/license/mit") || url.contains("mit-license") || url.contains("spdx.org/licenses/mit"); } private static boolean isBsd3(String url) { return url.contains("bsd-3-clause") || url.contains("new-bsd") || url.contains("revised-bsd") || url.contains("spdx.org/licenses/bsd-3-clause"); } private static boolean isBsd2(String url) { return url.contains("bsd-2-clause") || url.contains("spdx.org/licenses/bsd-2-clause"); } private static boolean isIsc(String url) { return url.contains("opensource.org/licenses/isc") || url.contains("isc-license") || url.contains("spdx.org/licenses/isc"); } private static boolean isCc0(String url) { return url.contains("creativecommons.org/publicdomain/zero") || url.contains("spdx.org/licenses/cc0"); } private static boolean isUnlicense(String url) { return url.contains("unlicense.org") || url.contains("spdx.org/licenses/unlicense"); } private static boolean isBsl(String url) { return url.contains("boost.org/license_1_0") || url.contains("spdx.org/licenses/bsl-1.0"); } private static boolean isPsf(String url) { return url.contains("python.org/psf") || url.contains("spdx.org/licenses/psf-2.0"); } private static boolean isArtistic2(String url) { return url.contains("artistic-license") || url.contains("artistic-2.0") || url.contains("spdx.org/licenses/artistic-2.0"); } } FILE: com.thomaskuenneth.mintime_67_src.tar.gz/app/src/main/java/com/thomaskuenneth/mintime/LicenseListAdapter.java /* * MIT License * * Copyright (c) 2026 Thomas Künneth * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.thomaskuenneth.mintime; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.ListAdapter; import com.google.android.material.listitem.ListItemLayout; import com.google.android.material.listitem.ListItemViewHolder; import java.util.List; import de.philipp_bobek.oss_licenses_parser.ThirdPartyLicense; final class LicenseListAdapter extends ListAdapter { private static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback<>() { @Override public boolean areItemsTheSame(@NonNull ThirdPartyLicense oldItem, @NonNull ThirdPartyLicense newItem) { return oldItem.getLibraryName().equals(newItem.getLibraryName()) && oldItem.getLicenseContent().equals(newItem.getLicenseContent()); } @Override public boolean areContentsTheSame(@NonNull ThirdPartyLicense oldItem, @NonNull ThirdPartyLicense newItem) { return oldItem.getLibraryName().equals(newItem.getLibraryName()) && oldItem.getLicenseContent().equals(newItem.getLicenseContent()); } }; interface Listener { void onLicenseClicked(@NonNull ThirdPartyLicense license); } private final Listener listener; LicenseListAdapter(@NonNull Listener listener) { super(DIFF_CALLBACK); this.listener = listener; } void setLicenses(List licenses) { submitList(licenses); } @NonNull @Override public LicenseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_license, parent, false); return new LicenseViewHolder(view); } @Override public void onBindViewHolder(@NonNull LicenseViewHolder holder, int position) { holder.bind(ListItemLayout.POSITION_SINGLE); ThirdPartyLicense license = getItem(position); holder.libraryName.setText(license.getLibraryName()); holder.licenseName.setText( LicenseNames.fromUrl(holder.itemView.getContext(), license.getLicenseContent())); holder.licenseCard.setOnClickListener(v -> listener.onLicenseClicked(license)); } static final class LicenseViewHolder extends ListItemViewHolder { final View licenseCard; final TextView libraryName; final TextView licenseName; LicenseViewHolder(@NonNull View itemView) { super(itemView); licenseCard = itemView.findViewById(R.id.license_card); libraryName = itemView.findViewById(R.id.library_name); licenseName = itemView.findViewById(R.id.license_name); } } } FILE: com.thomaskuenneth.mintime_67_src.tar.gz/app/src/main/java/com/thomaskuenneth/mintime/LicensesBottomSheet.java /* * MIT License * * Copyright (c) 2026 Thomas Künneth * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.thomaskuenneth.mintime; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.webkit.URLUtil; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import java.io.InputStream; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import de.philipp_bobek.oss_licenses_parser.OssLicensesParser; import de.philipp_bobek.oss_licenses_parser.ThirdPartyLicense; public class LicensesBottomSheet extends BottomSheetDialogFragment { private final ExecutorService executor = Executors.newSingleThreadExecutor(); private LicenseListAdapter adapter; private BottomSheetBehavior.BottomSheetCallback sheetCallback; @Override public int getTheme() { return R.style.ThemeOverlay_MinTime_BottomSheetDialog_Scrollable; } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.bottom_sheet_licenses, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); RecyclerView licenseList = view.findViewById(R.id.license_list); adapter = new LicenseListAdapter(this::openLicenseUrl); licenseList.setLayoutManager(new LinearLayoutManager(requireContext())); licenseList.setAdapter(adapter); loadLicenses(); } @Override public void onStart() { super.onStart(); BottomSheetDialog dialog = (BottomSheetDialog) requireDialog(); BottomSheetBehavior behavior = dialog.getBehavior(); behavior.setSkipCollapsed(true); behavior.setState(BottomSheetBehavior.STATE_EXPANDED); behavior.setPeekHeight(getResources().getDisplayMetrics().heightPixels / 2); View bottomSheet = dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); if (bottomSheet != null) { bottomSheet.post(() -> fitContentToVisibleSheet(dialog)); } sheetCallback = new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { fitContentToVisibleSheet(dialog); } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { fitContentToVisibleSheet(dialog); } }; behavior.addBottomSheetCallback(sheetCallback); } @Override public void onStop() { BottomSheetDialog dialog = (BottomSheetDialog) getDialog(); if (dialog != null && sheetCallback != null) { dialog.getBehavior().removeBottomSheetCallback(sheetCallback); } sheetCallback = null; super.onStop(); } @Override public void onDestroyView() { executor.shutdownNow(); super.onDestroyView(); } private void fitContentToVisibleSheet(@NonNull BottomSheetDialog dialog) { View content = getView(); View bottomSheet = dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet); CoordinatorLayout coordinator = dialog.findViewById(com.google.android.material.R.id.coordinator); if (content == null || bottomSheet == null || coordinator == null) { return; } int visibleHeight = coordinator.getBottom() - bottomSheet.getTop(); if (visibleHeight <= 0) { return; } ViewGroup.LayoutParams layoutParams = content.getLayoutParams(); if (layoutParams == null || layoutParams.height == visibleHeight) { return; } layoutParams.height = visibleHeight; content.setLayoutParams(layoutParams); } private void openLicenseUrl(@NonNull ThirdPartyLicense license) { String url = license.getLicenseContent().strip(); if (!URLUtil.isNetworkUrl(url)) { return; } startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); } private void loadLicenses() { var appContext = requireContext().getApplicationContext(); executor.execute(() -> { List licenses = readLicenses(appContext); if (!isAdded()) { return; } requireActivity().runOnUiThread(() -> adapter.setLicenses(licenses)); }); } private List readLicenses(android.content.Context context) { try (InputStream metadata = context.getResources() .openRawResource(R.raw.third_party_license_metadata); InputStream licenseFile = context.getResources() .openRawResource(R.raw.third_party_licenses)) { return OssLicensesParser.parseAllLicenses(metadata, licenseFile); } catch (Exception e) { return Collections.emptyList(); } } }