diff --git a/.kotlin/errors/errors-1762296211384.log b/.kotlin/errors/errors-1762296211384.log
new file mode 100644
index 0000000..b44ddf8
--- /dev/null
+++ b/.kotlin/errors/errors-1762296211384.log
@@ -0,0 +1,76 @@
+kotlin version: 2.0.21
+error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing C:/source/SmoothBottomBar/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt:15:5: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
+ at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
+ at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+Caused by: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
+ ... 33 more
+
+
diff --git a/.kotlin/errors/errors-1762296347665.log b/.kotlin/errors/errors-1762296347665.log
new file mode 100644
index 0000000..b44ddf8
--- /dev/null
+++ b/.kotlin/errors/errors-1762296347665.log
@@ -0,0 +1,76 @@
+kotlin version: 2.0.21
+error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing C:/source/SmoothBottomBar/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt:15:5: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
+ at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
+ at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+Caused by: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
+ ... 33 more
+
+
diff --git a/.kotlin/errors/errors-1762296420451.log b/.kotlin/errors/errors-1762296420451.log
new file mode 100644
index 0000000..b44ddf8
--- /dev/null
+++ b/.kotlin/errors/errors-1762296420451.log
@@ -0,0 +1,76 @@
+kotlin version: 2.0.21
+error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing C:/source/SmoothBottomBar/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt:15:5: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
+ at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
+ at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+Caused by: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
+ ... 33 more
+
+
diff --git a/.kotlin/errors/errors-1762296462947.log b/.kotlin/errors/errors-1762296462947.log
new file mode 100644
index 0000000..b44ddf8
--- /dev/null
+++ b/.kotlin/errors/errors-1762296462947.log
@@ -0,0 +1,76 @@
+kotlin version: 2.0.21
+error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing C:/source/SmoothBottomBar/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt:15:5: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
+ at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
+ at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+Caused by: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
+ ... 33 more
+
+
diff --git a/.kotlin/errors/errors-1762296578501.log b/.kotlin/errors/errors-1762296578501.log
new file mode 100644
index 0000000..b44ddf8
--- /dev/null
+++ b/.kotlin/errors/errors-1762296578501.log
@@ -0,0 +1,76 @@
+kotlin version: 2.0.21
+error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing C:/source/SmoothBottomBar/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt:15:5: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
+ at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
+ at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+Caused by: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
+ ... 33 more
+
+
diff --git a/.kotlin/errors/errors-1762296779307.log b/.kotlin/errors/errors-1762296779307.log
new file mode 100644
index 0000000..b44ddf8
--- /dev/null
+++ b/.kotlin/errors/errors-1762296779307.log
@@ -0,0 +1,76 @@
+kotlin version: 2.0.21
+error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing C:/source/SmoothBottomBar/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt:15:5: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
+ at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
+ at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+Caused by: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
+ ... 33 more
+
+
diff --git a/.kotlin/errors/errors-1762297506729.log b/.kotlin/errors/errors-1762297506729.log
new file mode 100644
index 0000000..b44ddf8
--- /dev/null
+++ b/.kotlin/errors/errors-1762297506729.log
@@ -0,0 +1,76 @@
+kotlin version: 2.0.21
+error message: org.jetbrains.kotlin.util.FileAnalysisException: While analysing C:/source/SmoothBottomBar/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt:15:5: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.util.AnalysisExceptionsKt.wrapIntoFileAnalysisExceptionIfNeeded(AnalysisExceptions.kt:57)
+ at org.jetbrains.kotlin.fir.FirCliExceptionHandler.handleExceptionOnFileAnalysis(Utils.kt:249)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:46)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.resolveAndCheckFir(firUtils.kt:77)
+ at org.jetbrains.kotlin.fir.pipeline.FirUtilsKt.buildResolveAndCheckFirViaLightTree(firUtils.kt:88)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModuleToAnalyzedFir(jvmCompilerPipeline.kt:319)
+ at org.jetbrains.kotlin.cli.jvm.compiler.pipeline.JvmCompilerPipelineKt.compileModulesUsingFrontendIrAndLightTree(jvmCompilerPipeline.kt:118)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:148)
+ at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103)
+ at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49)
+ at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:464)
+ at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:73)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:506)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:423)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:301)
+ at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:129)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:675)
+ at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:92)
+ at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1660)
+ at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
+ at java.base/java.lang.reflect.Method.invoke(Unknown Source)
+ at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
+ at java.base/java.security.AccessController.doPrivileged(Unknown Source)
+ at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+ at java.base/java.lang.Thread.run(Unknown Source)
+Caused by: java.lang.IllegalArgumentException: source must not be null
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.requireNotNull(KtDiagnosticReportHelpers.kt:68)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn(KtDiagnosticReportHelpers.kt:39)
+ at org.jetbrains.kotlin.diagnostics.KtDiagnosticReportHelpersKt.reportOn$default(KtDiagnosticReportHelpers.kt:31)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkSourceElement(FirIncompatibleClassExpressionChecker.kt:50)
+ at org.jetbrains.kotlin.fir.analysis.checkers.expression.FirIncompatibleClassExpressionChecker.checkType$checkers(FirIncompatibleClassExpressionChecker.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.checkers.type.FirIncompatibleClassTypeChecker.check(FirIncompatibleClassTypeChecker.kt:17)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.check(TypeCheckersDiagnosticComponent.kt:81)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:53)
+ at org.jetbrains.kotlin.fir.analysis.collectors.components.TypeCheckersDiagnosticComponent.visitResolvedTypeRef(TypeCheckersDiagnosticComponent.kt:19)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor.checkElement(CheckerRunningDiagnosticCollectorVisitor.kt:24)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:248)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitResolvedTypeRef(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.types.FirResolvedTypeRef.accept(FirResolvedTypeRef.kt:28)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl.acceptChildren(FirSimpleFunctionImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:118)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitSimpleFunction(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirSimpleFunction.accept(FirSimpleFunction.kt:51)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirRegularClassImpl.acceptChildren(FirRegularClassImpl.kt:63)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitWithDeclarationAndReceiver(AbstractDiagnosticCollectorVisitor.kt:311)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitClassAndChildren(AbstractDiagnosticCollectorVisitor.kt:87)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:92)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitRegularClass(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirRegularClass.accept(FirRegularClass.kt:48)
+ at org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl.acceptChildren(FirFileImpl.kt:57)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitNestedElements(AbstractDiagnosticCollectorVisitor.kt:38)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:1151)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor.visitFile(AbstractDiagnosticCollectorVisitor.kt:30)
+ at org.jetbrains.kotlin.fir.declarations.FirFile.accept(FirFile.kt:42)
+ at org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector.collectDiagnostics(AbstractDiagnosticCollector.kt:36)
+ at org.jetbrains.kotlin.fir.pipeline.AnalyseKt.runCheckers(analyse.kt:34)
+ ... 33 more
+
+
diff --git a/README.md b/README.md
index b43c51b..d017efe 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,13 @@
A lightweight Android material bottom navigation bar library
+exposed setBadge and removeBadge for jvm
+implementation 'com.github.Cherdenko:SmoothBottomBar:-SNAPSHOT'
+
[](https://jitpack.io/#ibrahimsn98/SmoothBottomBar)
-[](https://android-arsenal.com/api?level=22)
+[](https://android-arsenal.com/api?level=16)
[]( https://android-arsenal.com/details/1/7932 )
+[](https://androidweekly.net/issues/issue-385)
## GIF
@@ -12,7 +16,7 @@ A lightweight Android material bottom navigation bar library
## Design Credits
-All design and inspiration credits belongs to [Alejandro Ausejo](https://dribbble.com/shots/6251784-Navigation-Menu-Animation).
+All design and inspiration credits belong to [Alejandro Ausejo](https://dribbble.com/shots/6251784-Navigation-Menu-Animation).
## Usage
@@ -51,6 +55,7 @@ All design and inspiration credits belongs to [Alejandro Ausejo](https://dribbbl
android:layout_width="match_parent"
android:layout_height="70dp"
app:backgroundColor="@color/colorPrimary"
+ app:badgeColor="@color/colorBadge"
app:menu="@menu/menu_bottom"/>
```
@@ -65,6 +70,275 @@ bottomBar.onItemReselected = {
}
```
+OR
+
+```kotlin
+bottomBar.setOnItemSelectedListener(object: OnItemSelectedListener {
+ override fun onItemSelect(pos: Int) {
+ status.text = "Item $pos selected"
+ }
+})
+
+bottomBar.setOnItemReselectedListener(object: OnItemReselectedListener {
+ override fun onItemReselect(pos: Int) {
+ status.text = "Item $pos re-selected"
+ }
+})
+```
+
+ >**Note:** For projects without kotlin, you may need to add `org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion` to your dependencies since this is a Kotlin library.
+
+## **Use SmoothBottomBar with [Navigation Components](https://developer.android.com/guide/navigation/).**
+
+Coupled with the Navigation Component from the [Android Jetpack](https://developer.android.com/jetpack), SmoothBottomBar offers easier navigation within your application by designating navigation to the Navigation Component. This works best when using fragments, as the Navigation component helps to handle your fragment transactions.
+
+- Setup Navigation Component i.e. Add dependenccy to your project, create a Navigation Graph etc.
+- For each Fragment in your Navigation Graph, ensure that the Fragment's `id` is the same as the MenuItems in your Menu i.e res/menu/ folder
+```xml
+
+
+```
+
+Navigation Graph i.e res/navigation/ folder
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+- In your activity i.e `MainActivity`, create an instance of `PopupMenu` which takes a `context` and an `anchor`(pass in null) and then inflate this `PopupMenu` with the layout menu for the `SmoothBottomBar`.
+- Get a reference to your `SmoothBottomBar` and call `setupWithNavController()` which takes in a `Menu` and `NavController`, pass in the menu of the previously instantiated `PopupMenu` i.e.(`popUpMenu.menu`) and your `NavController`.
+- Preferably set this up in a function as shown below and call this function i.e. (`setupSmoothBottomMenu()`) in the `onCreate` method of your activity.
+
+**N.B:** Sample app makes use of [ViewBinding](https://developer.android.com/topic/libraries/view-binding) to get reference to views in the layout.
+
+```kotlin
+ private fun setupSmoothBottomMenu() {
+ binding.bottomBar.setupWithNavController(navController)
+ }
+```
+
+
+### ActionBar
+You can also setup your `ActionBar` with the Navigation Component by calling `setupActionBarWithNavController` and pass in your `NavController`.
+
+**N.B:** Your app needs to have a `Toolbar` for `setupActionBarWithNavController` to work. If your app theme doesn't have a `Toolbar` i.e. (Theme.AppCompat.Light.NoActionBar) you would need to:
+
+- Add one to your layout i.e.
+
+```xml
+
+
+
+```
+- Set the support action bar to your `Toolbar` using `setSupportActionBar(your_toolbar_id)` in this case `setSupportActionBar(binding.toolBar)`
+
+We now have something like this:
+
+```kotlin
+ private lateinit var navController: NavController
+ private lateinit var binding: ActivityMainBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ navController = findNavController(R.id.main_fragment)
+ setupActionBarWithNavController(navController)
+ setupSmoothBottomMenu()
+ }
+
+ private fun setupSmoothBottomMenu() {
+ binding.bottomBar.setupWithNavController(navController)
+ }
+
+ //set an active fragment programmatically
+ fun setSelectedItem(pos:Int){
+ binding.bottomBar.setSelectedItem(pos)
+ }
+ //set badge indicator
+ fun setBadge(pos:Int){
+ binding.bottomBar.setBadge(pos)
+ }
+ //remove badge indicator
+ fun removeBadge(pos:Int){
+ binding.bottomBar.removeBadge(pos)
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ return navController.navigateUp() || super.onSupportNavigateUp()
+ }
+```
+
+### Result Demo:
+
+
+
+### Update [8th May, 2021]
+Prior to the [initial addition of this feature](https://github.com/ibrahimsn98/SmoothBottomBar/pull/33), you can now inflate separate menu items for the `SmoothBottomBar` and your `Toolbar`.
+- Create the menu item you want to inflate in the `Toolbar` i.e.
+
+```xml
+
+
+```
+- Override `OnCreateOptionsMenu` and `onOptionsItemSelected` (ensure it returns `super.onOptionsItemSelected(item)`). Now we have:
+
+```kotlin
+ class MainActivity : AppCompatActivity() {
+ private lateinit var navController: NavController
+ private lateinit var binding: ActivityMainBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ navController = findNavController(R.id.main_fragment)
+ setupActionBarWithNavController(navController)
+ setupSmoothBottomMenu()
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.another_menu, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.another_item_1 -> {
+ showToast("Another Menu Item 1 Selected")
+ }
+
+ R.id.another_item_2 -> {
+ showToast("Another Menu Item 2 Selected")
+ }
+
+ R.id.another_item_3 -> {
+ showToast("Another Menu Item 3 Selected")
+ }
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+
+ private fun showToast(msg: String) {
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
+ }
+
+ private fun setupSmoothBottomMenu() {
+ binding.bottomBar.setupWithNavController(navController)
+ }
+
+ //set an active fragment programmatically
+ fun setSelectedItem(pos:Int){
+ binding.bottomBar.setSelectedItem(pos)
+ }
+ //set badge indicator
+ fun setBadge(pos:Int){
+ binding.bottomBar.setBadge(pos)
+ }
+ //remove badge indicator
+ fun removeBadge(pos:Int){
+ binding.bottomBar.removeBadge(pos)
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ return navController.navigateUp() || super.onSupportNavigateUp()
+ }
+}
+```
+
+### Select Bottom Item from any fragment
+```kotlin
+ buttonId.setOnClickListener {
+ (requireActivity() as MainActivity).setSelectedItem(2)
+ }
+```
+
+
+### Result Demo:
+
+
+
+
## Customization
```xml
@@ -72,35 +346,107 @@ bottomBar.onItemReselected = {
android:id="@+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="70dp"
+ app:menu=""
app:backgroundColor=""
- app:textColor=""
- app:textSize=""
- app:iconSize=""
app:indicatorColor=""
+ app:indicatorRadius=""
+ app:cornerRadius=""
+ app:corners=""
app:sideMargins=""
app:itemPadding=""
+ app:textColor=""
+ app:badgeColor=""
+ app:itemFontFamily=""
+ app:textSize=""
+ app:iconSize=""
app:iconTint=""
app:iconTintActive=""
app:activeItem=""
- app:duration=""
- app:menu=""/>
+ app:duration="" />
```
## Setup
+> Follow me on Twitter [@ibrahimsn98](https://twitter.com/ibrahimsn98)
+
```gradle
- allprojects {
- repositories {
- ...
- maven { url 'https://jitpack.io' }
- }
- }
-
- dependencies {
- implementation 'com.github.ibrahimsn98:SmoothBottomBar:1.4'
- }
+//project label build.gradle
+buildscript {
+ repositories {
+ ....
+ maven { url 'https://jitpack.io' }
+ }
+}
+
+allprojects {
+ repositories {
+ .......
+ maven { url 'https://www.jitpack.io' }
+ }
+}
+//app label build.gradle
+dependencies {
+ implementation 'com.github.ibrahimsn98:SmoothBottomBar:1.7.9'
+}
```
+## Contributors ✨
+
+
+
## License
```
diff --git a/app/build.gradle b/app/build.gradle
index 59ea6c9..53bdf12 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,37 +1,62 @@
apply plugin: 'com.android.application'
-
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
+def nav_version = "2.9.5"
android {
- compileSdkVersion 28
+ namespace 'me.ibrahimsn.smoothbottombar'
+ compileSdk = 36
+
defaultConfig {
applicationId "me.ibrahimsn.smoothbottombar"
- minSdkVersion 22
- targetSdkVersion 28
+ minSdkVersion 24
+ targetSdkVersion 36
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ multiDexEnabled true
}
+
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_21
+ targetCompatibility JavaVersion.VERSION_21
+ }
+
+ kotlinOptions {
+ jvmTarget = '21'
+ }
+
+ buildFeatures {
+ viewBinding true
+ dataBinding true
+ }
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.core:core-ktx:1.1.0'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
-
implementation project(":lib")
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ // ✅ Use a valid Kotlin version
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:2.2.21"
+
+ implementation 'androidx.appcompat:appcompat:1.7.1'
+ implementation 'androidx.core:core-ktx:1.17.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
+ implementation "androidx.multidex:multidex:2.0.1"
+ implementation project(":lib")
+ androidTestImplementation project(path: ':app')
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+
+ // Navigation Architecture Component
+ implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
+ implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
diff --git a/app/src/androidTest/java/me/ibrahimsn/smoothbottombar/ExampleInstrumentedTest.kt b/app/src/androidTest/java/me/ibrahimsn/smoothbottombar/ExampleInstrumentedTest.kt
deleted file mode 100644
index e48a601..0000000
--- a/app/src/androidTest/java/me/ibrahimsn/smoothbottombar/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package me.ibrahimsn.smoothbottombar
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("me.ibrahimsn.smoothbottombar", appContext.packageName)
- }
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 98c63d9..1693803 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,15 +1,16 @@
+
+>
-
+
diff --git a/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt b/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt
new file mode 100644
index 0000000..da573f1
--- /dev/null
+++ b/app/src/main/java/me/ibrahimsn/smoothbottombar/FirstFragment.kt
@@ -0,0 +1,29 @@
+package me.ibrahimsn.smoothbottombar
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+
+/**
+ * A simple [Fragment] subclass.
+ */
+class FirstFragment : Fragment(R.layout.fragment_first) {
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val textView=view.findViewById(R.id.textView)
+ textView.setOnClickListener {
+ (requireActivity() as MainActivity).setSelectedItem(2)
+ (requireActivity() as MainActivity).removeBadge(2)
+ }
+
+
+ (requireActivity() as MainActivity).setBadge(2)
+ (requireActivity() as MainActivity).setBadge(0)
+ }
+
+}
diff --git a/app/src/main/java/me/ibrahimsn/smoothbottombar/FourthFragment.kt b/app/src/main/java/me/ibrahimsn/smoothbottombar/FourthFragment.kt
new file mode 100644
index 0000000..9927e9f
--- /dev/null
+++ b/app/src/main/java/me/ibrahimsn/smoothbottombar/FourthFragment.kt
@@ -0,0 +1,22 @@
+package me.ibrahimsn.smoothbottombar
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+
+/**
+ * A simple [Fragment] subclass.
+ */
+class FourthFragment : Fragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_fourth, container, false)
+ }
+
+}
diff --git a/app/src/main/java/me/ibrahimsn/smoothbottombar/MainActivity.kt b/app/src/main/java/me/ibrahimsn/smoothbottombar/MainActivity.kt
index 4232648..4b7ea73 100644
--- a/app/src/main/java/me/ibrahimsn/smoothbottombar/MainActivity.kt
+++ b/app/src/main/java/me/ibrahimsn/smoothbottombar/MainActivity.kt
@@ -1,20 +1,79 @@
package me.ibrahimsn.smoothbottombar
import android.os.Bundle
+import android.view.Menu
+import android.view.MenuItem
+import android.widget.PopupMenu
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_main.*
+import androidx.navigation.NavController
+import androidx.navigation.findNavController
+import androidx.navigation.ui.setupActionBarWithNavController
-class MainActivity : AppCompatActivity(R.layout.activity_main) {
+import me.ibrahimsn.smoothbottombar.databinding.ActivityMainBinding
+import me.ibrahimsn.lib.*
+class MainActivity : AppCompatActivity() {
+ private lateinit var navController: NavController
+ private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ navController = findNavController(R.id.main_fragment)
+ setupActionBarWithNavController(navController)
+ setupSmoothBottomMenu()
+ }
- bottomBar.onItemSelected = {
- status.text = "Item $it selected"
- }
- bottomBar.onItemReselected = {
- status.text = "Item $it re-selected"
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.another_menu, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.another_item_1 -> {
+ showToast("Another Menu Item 1 Selected")
+ }
+
+ R.id.another_item_2 -> {
+ showToast("Another Menu Item 2 Selected")
+ }
+
+ R.id.another_item_3 -> {
+ showToast("Another Menu Item 3 Selected")
+ }
}
+ return super.onOptionsItemSelected(item)
+ }
+
+ //set an active fragment programmatically
+ fun setSelectedItem(pos:Int){
+ binding.bottomBar.setSelectedItem(pos)
+ }
+ //set badge indicator
+ fun setBadge(pos:Int){
+ binding.bottomBar.setBadge(pos)
+ }
+ //remove badge indicator
+ fun removeBadge(pos:Int){
+ binding.bottomBar.removeBadge(pos)
+ }
+
+ private fun showToast(msg: String) {
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
+ }
+
+ private fun setupSmoothBottomMenu() {
+ val popupMenu = PopupMenu(this, null)
+ popupMenu.inflate(R.menu.menu_bottom)
+ val menu = popupMenu.menu
+ //binding.bottomBar.setupWithNavController(menu, navController)
+ binding.bottomBar.setupWithNavController( navController)
+ }
+
+ override fun onSupportNavigateUp(): Boolean {
+ return navController.navigateUp() || super.onSupportNavigateUp()
}
}
diff --git a/app/src/main/java/me/ibrahimsn/smoothbottombar/SecondFragment.kt b/app/src/main/java/me/ibrahimsn/smoothbottombar/SecondFragment.kt
new file mode 100644
index 0000000..27eaafa
--- /dev/null
+++ b/app/src/main/java/me/ibrahimsn/smoothbottombar/SecondFragment.kt
@@ -0,0 +1,22 @@
+package me.ibrahimsn.smoothbottombar
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+
+/**
+ * A simple [Fragment] subclass.
+ */
+class SecondFragment : Fragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_second, container, false)
+ }
+
+}
diff --git a/app/src/main/java/me/ibrahimsn/smoothbottombar/ThirdFragment.kt b/app/src/main/java/me/ibrahimsn/smoothbottombar/ThirdFragment.kt
new file mode 100644
index 0000000..ac095a5
--- /dev/null
+++ b/app/src/main/java/me/ibrahimsn/smoothbottombar/ThirdFragment.kt
@@ -0,0 +1,22 @@
+package me.ibrahimsn.smoothbottombar
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+
+/**
+ * A simple [Fragment] subclass.
+ */
+class ThirdFragment : Fragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_third, container, false)
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index f75e671..bcca3f5 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -6,11 +6,13 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
-
diff --git a/app/src/main/res/layout/fragment_first.xml b/app/src/main/res/layout/fragment_first.xml
new file mode 100644
index 0000000..d332a6e
--- /dev/null
+++ b/app/src/main/res/layout/fragment_first.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_fourth.xml b/app/src/main/res/layout/fragment_fourth.xml
new file mode 100644
index 0000000..11750b7
--- /dev/null
+++ b/app/src/main/res/layout/fragment_fourth.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_second.xml b/app/src/main/res/layout/fragment_second.xml
new file mode 100644
index 0000000..13e8e06
--- /dev/null
+++ b/app/src/main/res/layout/fragment_second.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_third.xml b/app/src/main/res/layout/fragment_third.xml
new file mode 100644
index 0000000..f77dada
--- /dev/null
+++ b/app/src/main/res/layout/fragment_third.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/another_menu.xml b/app/src/main/res/menu/another_menu.xml
new file mode 100644
index 0000000..d79bd4d
--- /dev/null
+++ b/app/src/main/res/menu/another_menu.xml
@@ -0,0 +1,12 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_bottom.xml b/app/src/main/res/menu/menu_bottom.xml
index 8c4dfe3..5fccd25 100644
--- a/app/src/main/res/menu/menu_bottom.xml
+++ b/app/src/main/res/menu/menu_bottom.xml
@@ -2,23 +2,27 @@
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 0000000..2686232
--- /dev/null
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..01569c9
--- /dev/null
+++ b/app/src/main/res/values-ar/strings.xml
@@ -0,0 +1,8 @@
+
+
+ SmoothBottomBar
+ الرئيسية
+ ØØ³Ø§Ø¨ÙŠ
+ المتجر
+ المتصدرين
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index ad39811..52acda9 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -6,4 +6,5 @@
#ffffff
#A3FFFFFF
+ #f4d415
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b567c90..52be47b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,4 +5,7 @@
Leaderboard
Store
Profile
+
+
+ Hello blank fragment
diff --git a/build.gradle b/build.gradle
index f08173b..baae2e5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,26 +1,39 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
+def nav_version = "2.9.5"
+def agp_version = '8.13.0'
buildscript {
- ext.kotlin_version = '1.3.50'
+ ext.kotlin_version = '2.2.21'
+ ext {
+ agp_version = '8.13.0'
+ }
repositories {
- google()
- jcenter()
+ google()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.1'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.android.tools.build:gradle:$agp_version"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.21"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
-}
+
+}
+configurations.all {
+ resolutionStrategy {
+ force "org.jetbrains.kotlin:kotlin-stdlib:1.9.10"
+ }
+}
allprojects {
repositories {
google()
- jcenter()
+ mavenCentral()
+
}
+
}
task clean(type: Delete) {
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index f6b961f..980502d 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 951e07d..e3f9171 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,8 @@
-#Fri Oct 25 12:42:27 EET 2019
+#Tue Nov 04 23:36:10 CET 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
diff --git a/gradlew b/gradlew
index cccdd3d..faf9300 100755
--- a/gradlew
+++ b/gradlew
@@ -1,78 +1,129 @@
-#!/usr/bin/env sh
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -81,92 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=$((i+1))
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=$(save "$@")
-
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
-if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
- cd "$(dirname "$0")"
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
fi
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index f955316..9d21a21 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,4 +1,22 @@
-@if "%DEBUG%" == "" @echo off
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -9,25 +27,29 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -35,48 +57,36 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/lib/build.gradle b/lib/build.gradle
index 423e727..353e6d4 100644
--- a/lib/build.gradle
+++ b/lib/build.gradle
@@ -1,18 +1,19 @@
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
-android {
- compileSdkVersion 28
+
+ apply plugin: 'com.android.library'
+ apply plugin: 'kotlin-android'
+def nav_version = "2.9.5"
+android {
+ compileSdkVersion 36
+ namespace 'me.ibrahimsn.lib'
defaultConfig {
- minSdkVersion 22
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
+ minSdkVersion 24
+ targetSdkVersion 36
+ multiDexEnabled true
+
+
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
@@ -21,15 +22,24 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_21
+ targetCompatibility JavaVersion.VERSION_21
+ }
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_21
+ }
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'androidx.core:core-ktx:1.1.0'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.10"
+ implementation 'androidx.appcompat:appcompat:1.7.1'
+ implementation 'androidx.core:core-ktx:1.17.0'
+ implementation "androidx.multidex:multidex:2.0.1"
+
+ //Navigation Architecture Component
+ implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
+ implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
diff --git a/lib/src/main/AndroidManifest.xml b/lib/src/main/AndroidManifest.xml
index 556d76f..1f5c0c5 100644
--- a/lib/src/main/AndroidManifest.xml
+++ b/lib/src/main/AndroidManifest.xml
@@ -1,2 +1,10 @@
+ >
+
+
+
+
+
+
diff --git a/lib/src/main/java/me/ibrahimsn/lib/AccessibleExploreByTouchHelper.kt b/lib/src/main/java/me/ibrahimsn/lib/AccessibleExploreByTouchHelper.kt
new file mode 100644
index 0000000..f486fd2
--- /dev/null
+++ b/lib/src/main/java/me/ibrahimsn/lib/AccessibleExploreByTouchHelper.kt
@@ -0,0 +1,70 @@
+package me.ibrahimsn.lib
+
+import android.graphics.Rect
+import android.os.Bundle
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import androidx.customview.widget.ExploreByTouchHelper
+
+class AccessibleExploreByTouchHelper(
+ private val host : SmoothBottomBar,
+ private val bottomBarItems : List,
+ private val onClickAction : (id : Int) -> Unit
+) : ExploreByTouchHelper(host) {
+
+ override fun getVisibleVirtualViews(virtualViewIds: MutableList) {
+ // defining simple ids for each item of the bottom bar
+ for (i in bottomBarItems.indices) {
+ virtualViewIds.add(i)
+ }
+ }
+
+ override fun getVirtualViewAt(x: Float, y: Float): Int {
+ val itemWidth = host.width / bottomBarItems.size
+ return (x / itemWidth).toInt()
+ }
+
+ /**
+ * setBoundsInParent is required by [ExploreByTouchHelper]
+ */
+ @Suppress("DEPRECATION")
+ override fun onPopulateNodeForVirtualView(
+ virtualViewId: Int,
+ node: AccessibilityNodeInfoCompat
+ ) {
+ node.className = BottomBarItem::class.simpleName
+ node.contentDescription = bottomBarItems[virtualViewId].contentDescription
+ node.isClickable = true
+ node.isFocusable = true
+ node.isScreenReaderFocusable = true
+
+ node.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK)
+
+ node.isSelected = host.itemActiveIndex == virtualViewId
+
+ val bottomItemBoundRect = updateBoundsForBottomItem(virtualViewId)
+ node.setBoundsInParent(bottomItemBoundRect)
+ }
+
+ override fun onPerformActionForVirtualView(
+ virtualViewId: Int,
+ action: Int,
+ arguments: Bundle?
+ ): Boolean {
+ if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
+ onClickAction.invoke(virtualViewId)
+ return true
+ }
+ return false
+ }
+
+ private fun updateBoundsForBottomItem(index: Int): Rect {
+ val itemBounds = Rect()
+ val itemWidth = host.width / bottomBarItems.size
+ val left = index * itemWidth
+ itemBounds.left = left
+ itemBounds.top = 0
+ itemBounds.right = (left + itemWidth)
+ itemBounds.bottom = host.height
+ return itemBounds
+ }
+}
diff --git a/lib/src/main/java/me/ibrahimsn/lib/BottomBarItem.kt b/lib/src/main/java/me/ibrahimsn/lib/BottomBarItem.kt
index 74758e4..e353724 100644
--- a/lib/src/main/java/me/ibrahimsn/lib/BottomBarItem.kt
+++ b/lib/src/main/java/me/ibrahimsn/lib/BottomBarItem.kt
@@ -3,4 +3,10 @@ package me.ibrahimsn.lib
import android.graphics.RectF
import android.graphics.drawable.Drawable
-data class BottomBarItem(var title: String, val icon: Drawable, var rect: RectF = RectF(), var alpha: Int)
\ No newline at end of file
+data class BottomBarItem (
+ var title: String,
+ var contentDescription : String,
+ val icon: Drawable,
+ var rect: RectF = RectF(),
+ var alpha: Int
+)
diff --git a/lib/src/main/java/me/ibrahimsn/lib/BottomBarParser.kt b/lib/src/main/java/me/ibrahimsn/lib/BottomBarParser.kt
index 2be07a6..6f3acb9 100644
--- a/lib/src/main/java/me/ibrahimsn/lib/BottomBarParser.kt
+++ b/lib/src/main/java/me/ibrahimsn/lib/BottomBarParser.kt
@@ -1,14 +1,13 @@
package me.ibrahimsn.lib
import android.content.Context
+import android.content.res.Resources
import android.content.res.XmlResourceParser
import android.graphics.drawable.Drawable
+import androidx.annotation.XmlRes
import androidx.core.content.ContextCompat
-import me.ibrahimsn.lib.Constants.ICON_ATTRIBUTE
-import me.ibrahimsn.lib.Constants.ITEM_TAG
-import me.ibrahimsn.lib.Constants.TITLE_ATTRIBUTE
-class BottomBarParser(private val context: Context, res: Int) {
+internal class BottomBarParser(private val context: Context, @XmlRes res: Int) {
private val parser: XmlResourceParser = context.resources.getXml(res)
@@ -18,33 +17,55 @@ class BottomBarParser(private val context: Context, res: Int) {
do {
eventType = parser.next()
-
- if (eventType == XmlResourceParser.START_TAG && parser.name == ITEM_TAG)
+ if (eventType == XmlResourceParser.START_TAG && parser.name == ITEM_TAG) {
items.add(getTabConfig(parser))
-
+ }
} while (eventType != XmlResourceParser.END_DOCUMENT)
- return items.toList()
+ return items
}
private fun getTabConfig(parser: XmlResourceParser): BottomBarItem {
val attributeCount = parser.attributeCount
var itemText: String? = null
var itemDrawable: Drawable? = null
+ var contentDescription : String? = null
- for (i in 0 until attributeCount)
- when (parser.getAttributeName(i)) {
- ICON_ATTRIBUTE -> itemDrawable =
- ContextCompat.getDrawable(context, parser.getAttributeResourceValue(i, 0))
- TITLE_ATTRIBUTE -> {
- itemText = try {
- context.getString(parser.getAttributeResourceValue(i, 0))
- } catch (e: Exception) {
- parser.getAttributeValue(i)
- }
+ for (index in 0 until attributeCount) {
+ when (parser.getAttributeName(index)) {
+ ICON_ATTRIBUTE -> itemDrawable = ContextCompat.getDrawable(
+ context,
+ parser.getAttributeResourceValue(index, 0)
+ )
+ TITLE_ATTRIBUTE -> itemText = try {
+ context.getString(parser.getAttributeResourceValue(index, 0))
+ } catch (notFoundException: Resources.NotFoundException) {
+ parser.getAttributeValue(index)
+ }
+ CONTENT_DESCRIPTION_ATTRIBUTE -> contentDescription = try {
+ context.getString(parser.getAttributeResourceValue(index, 0))
+ } catch (notFoundException: Resources.NotFoundException) {
+ parser.getAttributeValue(index)
}
}
+ }
+
+ if (itemDrawable == null) {
+ throw Throwable("Item icon can not be null!")
+ }
+
+ return BottomBarItem(
+ itemText.toString(),
+ contentDescription ?: itemText.toString(),
+ itemDrawable,
+ alpha = 0
+ )
+ }
- return BottomBarItem(itemText ?: "", itemDrawable!!, alpha = 0)
+ companion object {
+ private const val ITEM_TAG = "item"
+ private const val ICON_ATTRIBUTE = "icon"
+ private const val TITLE_ATTRIBUTE = "title"
+ private const val CONTENT_DESCRIPTION_ATTRIBUTE = "contentDescription"
}
-}
\ No newline at end of file
+}
diff --git a/lib/src/main/java/me/ibrahimsn/lib/Constants.kt b/lib/src/main/java/me/ibrahimsn/lib/Constants.kt
deleted file mode 100644
index 6bee9a1..0000000
--- a/lib/src/main/java/me/ibrahimsn/lib/Constants.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package me.ibrahimsn.lib
-
-/**
- * This is a static class to hold constants
- */
-object Constants {
- const val ITEM_TAG = "item"
- const val ICON_ATTRIBUTE = "icon"
- const val TITLE_ATTRIBUTE = "title"
- const val WHITE_COLOR_HEX = "#FFFFFF"
-}
-
diff --git a/lib/src/main/java/me/ibrahimsn/lib/NavigationComponentHelper.kt b/lib/src/main/java/me/ibrahimsn/lib/NavigationComponentHelper.kt
new file mode 100644
index 0000000..d4b565c
--- /dev/null
+++ b/lib/src/main/java/me/ibrahimsn/lib/NavigationComponentHelper.kt
@@ -0,0 +1,73 @@
+package me.ibrahimsn.lib
+
+import android.os.Bundle
+import android.view.Menu
+import androidx.annotation.IdRes
+import androidx.navigation.NavController
+import androidx.navigation.NavDestination
+import androidx.navigation.ui.NavigationUI
+import java.lang.ref.WeakReference
+
+/**
+ * Created by Mayokun Adeniyi on 24/04/2020.
+ */
+class NavigationComponentHelper {
+
+ companion object {
+
+ fun setupWithNavController(
+ menu: Menu,
+ smoothBottomBar: SmoothBottomBar,
+ navController: NavController
+ ) {
+ smoothBottomBar.onItemSelectedListener = object : OnItemSelectedListener {
+ override fun onItemSelect(pos: Int): Boolean {
+ return NavigationUI.onNavDestinationSelected(menu.getItem(pos), navController)
+ }
+ }
+
+ val weakReference = WeakReference(smoothBottomBar)
+
+ navController.addOnDestinationChangedListener(object :
+ NavController.OnDestinationChangedListener {
+
+ override fun onDestinationChanged(
+ controller: NavController,
+ destination: NavDestination,
+ arguments: Bundle?
+ ) {
+ val view = weakReference.get()
+
+ if (view == null) {
+ navController.removeOnDestinationChangedListener(this)
+ return
+ }
+
+ for (h in 0 until menu.size()) {
+ val menuItem = menu.getItem(h)
+ if (matchDestination(destination, menuItem.itemId)) {
+ menuItem.isChecked = true
+ smoothBottomBar.itemActiveIndex = h
+ }
+ }
+ }
+ })
+ }
+
+ /**
+ * Determines whether the given `destId` matches the NavDestination. This handles
+ * both the default case (the destination's id matches the given id) and the nested case where
+ * the given id is a parent/grandparent/etc of the destination.
+ */
+ fun matchDestination(
+ destination: NavDestination,
+ @IdRes destId: Int
+ ): Boolean {
+ var currentDestination: NavDestination? = destination
+ while (currentDestination!!.id != destId && currentDestination.parent != null) {
+ currentDestination = currentDestination.parent
+ }
+ return currentDestination.id == destId
+ }
+ }
+}
diff --git a/lib/src/main/java/me/ibrahimsn/lib/OnItemReselectedListener.kt b/lib/src/main/java/me/ibrahimsn/lib/OnItemReselectedListener.kt
new file mode 100644
index 0000000..df38116
--- /dev/null
+++ b/lib/src/main/java/me/ibrahimsn/lib/OnItemReselectedListener.kt
@@ -0,0 +1,6 @@
+package me.ibrahimsn.lib
+
+interface OnItemReselectedListener {
+
+ fun onItemReselect(pos: Int)
+}
diff --git a/lib/src/main/java/me/ibrahimsn/lib/OnItemSelectedListener.kt b/lib/src/main/java/me/ibrahimsn/lib/OnItemSelectedListener.kt
new file mode 100644
index 0000000..93660aa
--- /dev/null
+++ b/lib/src/main/java/me/ibrahimsn/lib/OnItemSelectedListener.kt
@@ -0,0 +1,6 @@
+package me.ibrahimsn.lib
+
+interface OnItemSelectedListener {
+
+ fun onItemSelect(pos: Int): Boolean
+}
diff --git a/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt b/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt
index f708152..d38228b 100644
--- a/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt
+++ b/lib/src/main/java/me/ibrahimsn/lib/SmoothBottomBar.kt
@@ -8,48 +8,295 @@ import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
+import android.os.Build
import android.util.AttributeSet
+import android.view.Menu
import android.view.MotionEvent
import android.view.View
+import android.view.accessibility.AccessibilityEvent
import android.view.animation.DecelerateInterpolator
+import android.widget.PopupMenu
+import androidx.annotation.*
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat
-import me.ibrahimsn.lib.Constants.WHITE_COLOR_HEX
-import kotlin.math.abs
+import androidx.core.view.ViewCompat
+import androidx.navigation.NavController
+import androidx.navigation.Navigation
+import androidx.navigation.findNavController
+import androidx.navigation.ui.NavigationUI
+import me.ibrahimsn.lib.ext.d2p
+import kotlin.math.roundToInt
+
+class SmoothBottomBar @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = R.attr.SmoothBottomBarStyle
+) : View(context, attrs, defStyleAttr) {
+ // Dynamic Variables
+ private var itemWidth: Float = 0F
-class SmoothBottomBar : View {
-
- /**
- * Default attribute values
- */
- private var barBackgroundColor = Color.parseColor(WHITE_COLOR_HEX)
- private var barIndicatorColor = Color.parseColor("#2DFFFFFF")
- private var barSideMargins = d2p(10f)
+ private var currentIconTint = itemIconTintActive
- private var itemPadding = d2p(10f)
- private var itemAnimDuration = 300L
+ private var indicatorLocation = barSideMargins
+ private var _iconBackgroundColor: Int = Color.TRANSPARENT
+ private val iconBackgroundPaint = Paint().apply {
+ isAntiAlias = true
+ style = Paint.Style.FILL
+ color = _iconBackgroundColor
+ }
+ // New padding backing (in PX)
+ @Dimension
+ private var _iconBackgroundPadding: Float = context.d2p(DEFAULT_ICON_BG_PADDING)
+
+ // Public accessors
+ var iconBackgroundColor: Int
+ @ColorInt get() = _iconBackgroundColor
+ set(@ColorInt value) {
+ _iconBackgroundColor = value
+ iconBackgroundPaint.color = value
+ invalidate()
+ }
- private var itemIconSize = d2p(18f)
- private var itemIconMargin = d2p(4f)
- private var itemIconTint = Color.parseColor("#C8FFFFFF")
- private var itemIconTintActive = Color.parseColor(WHITE_COLOR_HEX)
+ var iconBackgroundPadding: Float
+ @Dimension get() = _iconBackgroundPadding
+ set(@Dimension value) {
+ _iconBackgroundPadding = value
+ invalidate()
+ }
- private var itemTextColor = Color.parseColor(WHITE_COLOR_HEX)
- private var itemTextSize = d2p(11.0f)
- private var itemFontFamily = 0
+ private val rect = RectF()
- /**
- * Dynamic variables
- */
- private var itemWidth = 0f
- private var activeItem = 0
- private var currentIconTint = itemIconTintActive
- private var indicatorLocation = barSideMargins
+ // Cache for performance optimization
+ private val iconBackgroundRect = RectF()
+ private var cachedTextHeight: Float = 0f
+ private var needsRecalculation = true
private var items = listOf()
- var onItemSelected: (Int) -> Unit = {}
- var onItemReselected: (Int) -> Unit = {}
+ // Attribute Defaults
+ @ColorInt
+ private var _barBackgroundColor = Color.WHITE
+
+ @ColorInt
+ private var _barIndicatorColor = Color.parseColor(DEFAULT_INDICATOR_COLOR)
+
+ @Dimension
+ private var _barIndicatorRadius = context.d2p(DEFAULT_CORNER_RADIUS)
+
+ @Dimension
+ private var _barSideMargins = context.d2p(DEFAULT_SIDE_MARGIN)
+
+ @Dimension
+ private var _barCornerRadius = context.d2p(DEFAULT_BAR_CORNER_RADIUS)
+
+ private var _barCorners = DEFAULT_BAR_CORNERS
+
+ @Dimension
+ private var _itemPadding = context.d2p(DEFAULT_ITEM_PADDING)
+
+ @Dimension
+ private var _itemSpacing = context.d2p(DEFAULT_ITEM_SPACING)
+
+ private var _itemAnimDuration = DEFAULT_ANIM_DURATION
+
+ @Dimension
+ private var _itemIconSize = context.d2p(DEFAULT_ICON_SIZE)
+
+ @Dimension
+ private var _itemIconMargin = context.d2p(DEFAULT_ICON_MARGIN)
+
+ @ColorInt
+ private var _itemIconTint = Color.parseColor(DEFAULT_TINT)
+
+ @ColorInt
+ private var _itemIconTintActive = Color.WHITE
+
+ @ColorInt
+ private var _itemTextColor = Color.WHITE
+
+ @ColorInt
+ private var _itemBadgeColor = Color.RED
+
+ @Dimension
+ private var _itemTextSize = context.d2p(DEFAULT_TEXT_SIZE)
+
+ @FontRes
+ private var _itemFontFamily: Int = INVALID_RES
+
+ @XmlRes
+ private var _itemMenuRes: Int = INVALID_RES
+
+ private var _itemActiveIndex: Int = 0
+
+ lateinit var menu: Menu
+
+
+ private val badge_arr = HashSet()
+
+ // Core Attributes
+ var barBackgroundColor: Int
+ @ColorInt get() = _barBackgroundColor
+ set(@ColorInt value) {
+ _barBackgroundColor = value
+ paintBackground.color = value
+ invalidate()
+ }
+
+ var barIndicatorColor: Int
+ @ColorInt get() = _barIndicatorColor
+ set(@ColorInt value) {
+ _barIndicatorColor = value
+ paintIndicator.color = value
+ invalidate()
+ }
+
+ var barIndicatorRadius: Float
+ @Dimension get() = _barIndicatorRadius
+ set(@Dimension value) {
+ _barIndicatorRadius = value
+ invalidate()
+ }
+
+ var barSideMargins: Float
+ @Dimension get() = _barSideMargins
+ set(@Dimension value) {
+ _barSideMargins = value
+ invalidate()
+ }
+
+ var barCornerRadius: Float
+ @Dimension get() = _barCornerRadius
+ set(@Dimension value) {
+ _barCornerRadius = value
+ invalidate()
+ }
+
+ var barCorners: Int
+ get() = _barCorners
+ set(value) {
+ _barCorners = value
+ invalidate()
+ }
+
+ var itemTextSize: Float
+ @Dimension get() = _itemTextSize
+ set(@Dimension value) {
+ _itemTextSize = value
+ paintText.textSize = value
+ invalidate()
+ }
+
+ var itemTextColor: Int
+ @ColorInt get() = _itemTextColor
+ set(@ColorInt value) {
+ _itemTextColor = value
+ paintText.color = value
+ invalidate()
+ }
+ var itemBadgeColor: Int
+ @ColorInt get() = _itemBadgeColor
+ set(@ColorInt value) {
+ _itemBadgeColor = value
+ badgePaint.color = value
+ invalidate()
+ }
+
+ var itemPadding: Float
+ @Dimension get() = _itemPadding
+ set(@Dimension value) {
+ _itemPadding = value
+ needsRecalculation = true
+ invalidate()
+ }
+
+ var itemSpacing: Float
+ @Dimension get() = _itemSpacing
+ set(@Dimension value) {
+ _itemSpacing = value
+ needsRecalculation = true
+ invalidate()
+ }
+
+ var itemAnimDuration: Long
+ get() = _itemAnimDuration
+ set(value) {
+ _itemAnimDuration = value
+ }
+
+ var itemIconSize: Float
+ @Dimension get() = _itemIconSize
+ set(@Dimension value) {
+ _itemIconSize = value
+ invalidate()
+ }
+
+ var itemIconMargin: Float
+ @Dimension get() = _itemIconMargin
+ set(@Dimension value) {
+ _itemIconMargin = value
+ invalidate()
+ }
+
+ var itemIconTint: Int
+ @ColorInt get() = _itemIconTint
+ set(@ColorInt value) {
+ _itemIconTint = value
+ invalidate()
+ }
+
+ var itemIconTintActive: Int
+ @ColorInt get() = _itemIconTintActive
+ set(@ColorInt value) {
+ _itemIconTintActive = value
+ invalidate()
+ }
+
+ var itemFontFamily: Int
+ @FontRes get() = _itemFontFamily
+ set(@FontRes value) {
+ _itemFontFamily = value
+ if (value != INVALID_RES) {
+ paintText.typeface = ResourcesCompat.getFont(context, value)
+ invalidate()
+ }
+ }
+
+ var itemMenuRes: Int
+ @XmlRes get() = _itemMenuRes
+ set(value) {
+ _itemMenuRes = value
+ val popupMenu = PopupMenu(context, null)
+ popupMenu.inflate(value)
+ this.menu = popupMenu.menu
+ if (value != INVALID_RES) {
+ items = BottomBarParser(context, value).parse()
+ invalidate()
+ }
+ }
+
+ var itemActiveIndex: Int
+ get() = _itemActiveIndex
+ set(value) {
+ _itemActiveIndex = value
+ applyItemActiveIndex()
+ }
+
+
+ // Listeners
+ var onItemSelectedListener: OnItemSelectedListener? = null
+
+ var onItemReselectedListener: OnItemReselectedListener? = null
+
+ var onItemSelected: ((Int) -> Unit)? = null
+
+ var onItemReselected: ((Int) -> Unit)? = null
+
+ // Paints
+ private val paintBackground = Paint().apply {
+ isAntiAlias = true
+ style = Paint.Style.FILL
+ color = barIndicatorColor
+ }
private val paintIndicator = Paint().apply {
isAntiAlias = true
@@ -57,7 +304,13 @@ class SmoothBottomBar : View {
color = barIndicatorColor
}
- private val paintText= Paint().apply {
+ private val badgePaint = Paint().apply {
+ isAntiAlias = true
+ style = Paint.Style.FILL
+ color = itemBadgeColor
+ }
+
+ private val paintText = Paint().apply {
isAntiAlias = true
style = Paint.Style.FILL
color = itemTextColor
@@ -66,158 +319,559 @@ class SmoothBottomBar : View {
isFakeBoldText = true
}
- constructor(context: Context) : super(context)
- constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
- val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.SmoothBottomBar, 0, 0)
- barBackgroundColor = typedArray.getColor(R.styleable.SmoothBottomBar_backgroundColor, this.barBackgroundColor)
- barIndicatorColor = typedArray.getColor(R.styleable.SmoothBottomBar_indicatorColor, this.barIndicatorColor)
- barSideMargins = typedArray.getDimension(R.styleable.SmoothBottomBar_sideMargins, this.barSideMargins)
- itemPadding = typedArray.getDimension(R.styleable.SmoothBottomBar_itemPadding, this.itemPadding)
- itemTextColor = typedArray.getColor(R.styleable.SmoothBottomBar_textColor, this.itemTextColor)
- itemTextSize = typedArray.getDimension(R.styleable.SmoothBottomBar_textSize, this.itemTextSize)
- itemIconSize = typedArray.getDimension(R.styleable.SmoothBottomBar_iconSize, this.itemIconSize)
- itemIconTint = typedArray.getColor(R.styleable.SmoothBottomBar_iconTint, this.itemIconTint)
- itemIconTintActive = typedArray.getColor(R.styleable.SmoothBottomBar_iconTintActive, this.itemIconTintActive)
- activeItem = typedArray.getInt(R.styleable.SmoothBottomBar_activeItem, this.activeItem)
- itemFontFamily = typedArray.getResourceId(R.styleable.SmoothBottomBar_itemFontFamily, this.itemFontFamily)
- itemAnimDuration = typedArray.getInt(R.styleable.SmoothBottomBar_duration, this.itemAnimDuration.toInt()).toLong()
- items = BottomBarParser(context, typedArray.getResourceId(R.styleable.SmoothBottomBar_menu, 0)).parse()
- typedArray.recycle()
+ private var exploreByTouchHelper: AccessibleExploreByTouchHelper
- setBackgroundColor(barBackgroundColor)
+ init {
+ obtainStyledAttributes(attrs, defStyleAttr)
+ exploreByTouchHelper = AccessibleExploreByTouchHelper(this, items, ::onClickAction)
- // Update default attribute values
- paintIndicator.color = barIndicatorColor
- paintText.color = itemTextColor
- paintText.textSize = itemTextSize
+ ViewCompat.setAccessibilityDelegate(this, exploreByTouchHelper)
- if (itemFontFamily != 0)
- paintText.typeface = ResourcesCompat.getFont(context, itemFontFamily)
+ // Enable hardware acceleration for better performance
+ setLayerType(LAYER_TYPE_HARDWARE, null)
+ }
+
+ private fun obtainStyledAttributes(attrs: AttributeSet?, defStyleAttr: Int) {
+ val typedArray = context.theme.obtainStyledAttributes(
+ attrs,
+ R.styleable.SmoothBottomBar,
+ defStyleAttr,
+ 0
+ )
+
+ try {
+ iconBackgroundColor = typedArray.getColor(
+ R.styleable.SmoothBottomBar_iconBackgroundColor,
+ iconBackgroundColor
+ )
+ iconBackgroundPadding = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_iconBackgroundPadding,
+ iconBackgroundPadding
+ )
+ barBackgroundColor = typedArray.getColor(
+ R.styleable.SmoothBottomBar_backgroundColor,
+ barBackgroundColor
+ )
+ barIndicatorColor = typedArray.getColor(
+ R.styleable.SmoothBottomBar_indicatorColor,
+ barIndicatorColor
+ )
+ barIndicatorRadius = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_indicatorRadius,
+ barIndicatorRadius
+ )
+ barSideMargins = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_sideMargins,
+ barSideMargins
+ )
+ barCornerRadius = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_cornerRadius,
+ barCornerRadius
+ )
+ barCorners = typedArray.getInteger(
+ R.styleable.SmoothBottomBar_corners,
+ barCorners
+ )
+ itemPadding = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_itemPadding,
+ itemPadding
+ )
+ itemSpacing = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_itemSpacing,
+ itemSpacing
+ )
+ itemTextColor = typedArray.getColor(
+ R.styleable.SmoothBottomBar_textColor,
+ itemTextColor
+ )
+ itemTextSize = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_textSize,
+ itemTextSize
+ )
+ itemIconSize = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_iconSize,
+ itemIconSize
+ )
+ itemIconMargin = typedArray.getDimension(
+ R.styleable.SmoothBottomBar_iconMargin,
+ itemIconMargin
+ )
+ itemIconTint = typedArray.getColor(
+ R.styleable.SmoothBottomBar_iconTint,
+ itemIconTint
+ )
+ itemBadgeColor = typedArray.getColor(
+ R.styleable.SmoothBottomBar_badgeColor,
+ itemBadgeColor
+ )
+ itemIconTintActive = typedArray.getColor(
+ R.styleable.SmoothBottomBar_iconTintActive,
+ itemIconTintActive
+ )
+ itemActiveIndex = typedArray.getInt(
+ R.styleable.SmoothBottomBar_activeItem,
+ itemActiveIndex
+ )
+ itemFontFamily = typedArray.getResourceId(
+ R.styleable.SmoothBottomBar_itemFontFamily,
+ itemFontFamily
+ )
+ itemAnimDuration = typedArray.getInt(
+ R.styleable.SmoothBottomBar_duration,
+ itemAnimDuration.toInt()
+ ).toLong()
+ itemMenuRes = typedArray.getResourceId(
+ R.styleable.SmoothBottomBar_menu,
+ itemMenuRes
+ )
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ typedArray.recycle()
+ }
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
+ calculateItemBounds()
- var lastX = barSideMargins
- itemWidth = (width - barSideMargins * 2) / items.size
-
- for (item in items) {
- // Prevent text overflow by shortening the item title
- var shorted = false
- while (paintText.measureText(item.title) > itemWidth - itemIconSize - itemIconMargin - (itemPadding*2)) {
- item.title = item.title.dropLast(1)
- shorted = true
+ // Set initial active item state without animation
+ if (items.isNotEmpty()) {
+ for ((index, item) in items.withIndex()) {
+ item.alpha = if (index == itemActiveIndex) OPAQUE else TRANSPARENT
}
+ indicatorLocation = items[itemActiveIndex].rect.left
+ currentIconTint = itemIconTintActive
+ invalidate()
+ }
+ }
+
+ private fun calculateItemBounds() {
+ if (items.isEmpty() || width == 0 || height == 0) return
- // Add ellipsis character to item text if it is shorted
- if (shorted) {
- item.title = item.title.dropLast(1)
- item.title += context.getString(R.string.ellipsis)
+ // Calculate total spacing between items
+ val totalSpacing = if (items.size > 1) itemSpacing * (items.size - 1) else 0f
+
+ // Calculate available width after margins and spacing
+ val totalAvailableWidth = width - (barSideMargins * 2) - totalSpacing
+
+ // Calculate minimum width for inactive items (icon + padding only)
+ val inactiveItemWidth = itemIconSize + (itemPadding * 2)
+
+ // Calculate total width needed for inactive items
+ val totalInactiveWidth = inactiveItemWidth * (items.size - 1)
+
+ // Active item gets remaining space (ensures text fits and spreads across bar)
+ val activeItemWidth = totalAvailableWidth - totalInactiveWidth
+
+ var lastX = barSideMargins
+
+ // reverse items layout order if layout direction is RTL
+ val isRTL = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
+ && layoutDirection == LAYOUT_DIRECTION_RTL
+ val itemsToLayout = if (isRTL) items.reversed() else items
+
+ for ((index, item) in itemsToLayout.withIndex()) {
+ val actualIndex = if (isRTL) items.size - 1 - index else index
+
+ // Assign width based on active state
+ val currentItemWidth = if (actualIndex == itemActiveIndex) {
+ activeItemWidth
+ } else {
+ inactiveItemWidth
}
- item.rect = RectF(lastX, 0f, itemWidth + lastX, height.toFloat())
- lastX += itemWidth
+ item.rect.set(lastX, 0f, currentItemWidth + lastX, height.toFloat())
+ lastX += currentItemWidth + itemSpacing
+ }
+
+ // Update itemWidth to match active item width for indicator
+ if (_itemActiveIndex in items.indices) {
+ itemWidth = items[_itemActiveIndex].rect.width()
}
- // Set initial active item
- setActiveItem(activeItem)
+ // Cache text height calculation
+ cachedTextHeight = (paintText.descent() + paintText.ascent()) / 2
+ needsRecalculation = false
}
- override fun onDraw(canvas: Canvas) {
- super.onDraw(canvas)
+ @JvmName("setBadge")
+ fun setBadge(pos: Int) {
+ badge_arr.add(pos)
+ invalidate()
+ }
- val textHeight = (paintText.descent() + paintText.ascent()) / 2
+ @JvmName("removeBadge")
+ fun removeBadge(pos: Int) {
+ badge_arr.remove(pos)
+ invalidate()
+ }
- for ((i, item) in items.withIndex()) {
- val textLength = paintText.measureText(item.title)
- item.icon.mutate()
- item.icon.setBounds(item.rect.centerX().toInt() - itemIconSize.toInt() / 2 - ((textLength/2) * (1-(255 - item.alpha) / 255f)).toInt(),
- height / 2 - itemIconSize.toInt() / 2,
- item.rect.centerX().toInt() + itemIconSize.toInt() / 2 - ((textLength/2) * (1-(255 - item.alpha) / 255f)).toInt(),
- height / 2 + itemIconSize.toInt() / 2)
- this.paintText.alpha = item.alpha
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+
+ // Draw background
+ if (barCornerRadius > 0) {
+ canvas.drawRoundRect(
+ 0f, 0f,
+ width.toFloat(),
+ height.toFloat(),
+ minOf(barCornerRadius.toFloat(), height.toFloat() / 2),
+ minOf(barCornerRadius.toFloat(), height.toFloat() / 2),
+ paintBackground
+ )
+
+ if (barCorners != ALL_CORNERS) {
+
+ if ((barCorners and TOP_LEFT_CORNER) != TOP_LEFT_CORNER) {
+ // Draw a box to cover the curve on the top left
+ canvas.drawRect(
+ 0f, 0f, width.toFloat() / 2,
+ height.toFloat() / 2, paintBackground
+ )
+ }
+
+ if ((barCorners and TOP_RIGHT_CORNER) != TOP_RIGHT_CORNER) {
+ // Draw a box to cover the curve on the top right
+ canvas.drawRect(
+ width.toFloat() / 2, 0f, width.toFloat(),
+ height.toFloat() / 2, paintBackground
+ )
+ }
+
+ if ((barCorners and BOTTOM_LEFT_CORNER) != BOTTOM_LEFT_CORNER) {
+ // Draw a box to cover the curve on the bottom left
+ canvas.drawRect(
+ 0f, height.toFloat() / 2, width.toFloat() / 2,
+ height.toFloat(), paintBackground
+ )
+ }
+
+ if ((barCorners and BOTTOM_RIGHT_CORNER) != BOTTOM_RIGHT_CORNER) {
+ // Draw a box to cover the curve on the bottom right
+ canvas.drawRect(
+ width.toFloat() / 2, height.toFloat() / 2, width.toFloat(),
+ height.toFloat(), paintBackground
+ )
+ }
- DrawableCompat.setTint(item.icon , if (i == activeItem) currentIconTint else itemIconTint)
- item.icon.draw(canvas)
+ }
- canvas.drawText(item.title, item.rect.centerX() + itemIconSize/2 + itemIconMargin,
- item.rect.centerY() - textHeight, paintText)
+ } else {
+ canvas.drawRect(
+ 0f, 0f,
+ width.toFloat(),
+ height.toFloat(),
+ paintBackground
+ )
}
// Draw indicator
- canvas.drawRoundRect(indicatorLocation,
- items[activeItem].rect.centerY() - itemIconSize/2 - itemPadding,
- indicatorLocation + itemWidth,
- items[activeItem].rect.centerY() + itemIconSize/2 + itemPadding,
- 20f, 20f, paintIndicator)
+ rect.left = indicatorLocation
+ rect.top = items[itemActiveIndex].rect.centerY() - itemIconSize / 2 - itemPadding
+ rect.right = indicatorLocation + itemWidth
+ rect.bottom = items[itemActiveIndex].rect.centerY() + itemIconSize / 2 + itemPadding
+
+ canvas.drawRoundRect(
+ rect,
+ barIndicatorRadius,
+ barIndicatorRadius,
+ paintIndicator
+ )
+
+ // Use cached text height
+ val textHeight = cachedTextHeight
+
+ // Pre-calculate common values
+ val halfHeight = height / 2
+ val halfIconSize = itemIconSize.toInt() / 2
+ val opaqueFloat = OPAQUE.toFloat()
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
+ && layoutDirection == LAYOUT_DIRECTION_RTL
+ ) {
+ for ((index, item) in items.withIndex()) {
+ val textLength = paintText.measureText(item.title)
+ val alphaFactor = (1 - (OPAQUE - item.alpha) / opaqueFloat)
+ val textOffset = ((textLength / 2) * alphaFactor).toInt()
+ val centerX = item.rect.centerX().toInt()
+
+ item.icon.mutate()
+ item.icon.setBounds(
+ centerX - halfIconSize + textOffset,
+ halfHeight - halfIconSize,
+ centerX + halfIconSize + textOffset,
+ halfHeight + halfIconSize
+ )
+ if (index != itemActiveIndex) {
+ drawIconBackground(item, index, canvas)
+ }
+ tintAndDrawIcon(item, index, canvas)
+
+ paintText.alpha = item.alpha
+ canvas.drawText(
+ item.title,
+ item.rect.centerX() - (itemIconSize / 2 + itemIconMargin),
+ item.rect.centerY() - textHeight, paintText
+ )
+ }
+
+ } else {
+ for ((index, item) in items.withIndex()) {
+ val textLength = paintText.measureText(item.title)
+ val alphaFactor = (1 - (OPAQUE - item.alpha) / opaqueFloat)
+ val textOffset = ((textLength / 2) * alphaFactor).toInt()
+ val centerX = item.rect.centerX().toInt()
+
+ item.icon.mutate()
+ item.icon.setBounds(
+ centerX - halfIconSize - textOffset,
+ halfHeight - halfIconSize,
+ centerX + halfIconSize - textOffset,
+ halfHeight + halfIconSize
+ )
+ //set badge indicator
+
+ if (index != itemActiveIndex) {
+ drawIconBackground(item, index, canvas)
+ }
+ tintAndDrawIcon(item, index, canvas)
+ if (badge_arr.contains(index)) {
+ canvas.drawCircle(
+ centerX - halfIconSize.toFloat() - ((textLength / 2) * alphaFactor),
+ halfHeight.toFloat() - halfIconSize.toFloat(),
+ 10f,
+ badgePaint
+ )
+ }
+ paintText.alpha = item.alpha
+ canvas.drawText(
+ item.title,
+ item.rect.centerX() + itemIconSize / 2 + itemIconMargin,
+ item.rect.centerY() - textHeight, paintText
+ )
+ }
+ }
+ }
+ // New: draw icon background behind non-active icons
+
+ private fun drawIconBackground(
+ item: BottomBarItem,
+ index: Int,
+ canvas: Canvas
+ ) {
+ // Skip if not requested
+ if (iconBackgroundColor == Color.TRANSPARENT) return
+
+ val cx = item.rect.centerX()
+ val cy = height / 2f
+ val half = itemIconSize / 2f
+
+ val left = cx - half - _iconBackgroundPadding
+ val top = cy - half - _iconBackgroundPadding
+ val right = cx + half + _iconBackgroundPadding
+ val bottom = cy + half + _iconBackgroundPadding
+ val radius = half + _iconBackgroundPadding
+
+ // Reuse cached RectF object to avoid allocation
+ iconBackgroundRect.set(left, top, right, bottom)
+ canvas.drawRoundRect(iconBackgroundRect, radius, radius, iconBackgroundPaint)
+ }
+ private fun tintAndDrawIcon(
+ item: BottomBarItem,
+ index: Int,
+ canvas: Canvas
+ ) {
+ DrawableCompat.setTint(
+ item.icon,
+ if (index == itemActiveIndex) currentIconTint else itemIconTint
+ )
+
+ item.icon.draw(canvas)
}
/**
* Handle item clicks
*/
@SuppressLint("ClickableViewAccessibility")
- override fun onTouchEvent(event: MotionEvent): Boolean {
- if (event.action == MotionEvent.ACTION_UP && abs(event.downTime - event.eventTime) < 500)
- for ((itemId, item) in items.withIndex())
- if (item.rect.contains(event.x, event.y))
- if (itemId != this.activeItem) {
- setActiveItem(itemId)
- onItemSelected(itemId)
- } else
- onItemReselected(itemId)
+ override fun onTouchEvent(event: MotionEvent?): Boolean {
+ when (event?.action) {
+ MotionEvent.ACTION_DOWN -> {
+ return true
+ }
- return true
+ MotionEvent.ACTION_UP -> {
+ for ((i, item) in items.withIndex()) {
+ if (item.rect.contains(event.x, event.y)) {
+ onClickAction(i)
+ break
+ }
+ }
+ }
+ }
+ return super.onTouchEvent(event)
}
- fun setActiveItem(pos: Int) {
- activeItem = pos
+ override fun dispatchHoverEvent(event: MotionEvent): Boolean {
+ return exploreByTouchHelper.dispatchHoverEvent(event) || super.dispatchHoverEvent(event)
+ }
- animateIndicator(pos)
+ private fun onClickAction(viewId: Int) {
+ exploreByTouchHelper.invalidateVirtualView(viewId)
+ if (viewId != itemActiveIndex) {
+ itemActiveIndex = viewId
+ onItemSelected?.invoke(viewId)
+ onItemSelectedListener?.onItemSelect(viewId)
+ } else {
+ onItemReselected?.invoke(viewId)
+ onItemReselectedListener?.onItemReselect(viewId)
+ }
+ exploreByTouchHelper.sendEventForVirtualView(
+ viewId,
+ AccessibilityEvent.TYPE_VIEW_CLICKED
+ )
+ }
- for ((i, item) in items.withIndex())
- animateAlpha(item, if (i == pos) 255 else 0)
+ private fun applyItemActiveIndex() {
+ if (items.isNotEmpty()) {
+ // Store old indicator location before recalculating bounds
+ val oldIndicatorLocation = indicatorLocation
+ val oldItemWidth = itemWidth
+
+ // Recalculate item bounds with new active index
+ calculateItemBounds()
+
+ for ((index, item) in items.withIndex()) {
+ if (index == itemActiveIndex) {
+ // Set initial state immediately if not animated
+ if (item.alpha == TRANSPARENT) {
+ item.alpha = OPAQUE
+ }
+ animateAlpha(item, OPAQUE)
+ } else {
+ animateAlpha(item, TRANSPARENT)
+ }
+ }
+
+ // Animate indicator position and width smoothly
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = itemAnimDuration
+ interpolator = DecelerateInterpolator()
+ addUpdateListener { animation ->
+ val progress = animation.animatedValue as Float
+ indicatorLocation = oldIndicatorLocation +
+ (items[itemActiveIndex].rect.left - oldIndicatorLocation) * progress
+ invalidate()
+ }
+ start()
+ }
- animateIconTint()
+ ValueAnimator.ofObject(ArgbEvaluator(), itemIconTint, itemIconTintActive).apply {
+ duration = itemAnimDuration
+ addUpdateListener {
+ currentIconTint = it.animatedValue as Int
+ }
+ start()
+ }
+ }
}
private fun animateAlpha(item: BottomBarItem, to: Int) {
- val animator = ValueAnimator.ofInt(item.alpha, to)
- animator.duration = itemAnimDuration
-
- animator.addUpdateListener {
- val value = it.animatedValue as Int
- item.alpha = value
- invalidate()
+ ValueAnimator.ofInt(item.alpha, to).apply {
+ duration = itemAnimDuration
+ addUpdateListener {
+ val value = it.animatedValue as Int
+ item.alpha = value
+ invalidate()
+ }
+ start()
}
+ }
- animator.start()
+ fun setupWithNavController(menu: Menu, navController: NavController) {
+ NavigationComponentHelper.setupWithNavController(menu, this, navController)
}
- private fun animateIndicator(pos: Int) {
- val animator = ValueAnimator.ofFloat(indicatorLocation, items[pos].rect.left)
- animator.duration = itemAnimDuration
- animator.interpolator = DecelerateInterpolator()
+ fun setupWithNavController(navController: NavController) {
+ NavigationComponentHelper.setupWithNavController(this.menu, this, navController)
+ Navigation.setViewNavController(this, navController)
+ }
- animator.addUpdateListener { animation ->
- indicatorLocation = animation.animatedValue as Float
+ fun setSelectedItem(pos: Int) {
+ try {
+ this.itemActiveIndex = pos
+ NavigationUI.onNavDestinationSelected(this.menu.getItem(pos), this.findNavController())
+ invalidate()
+ } catch (e: Exception) {
+ throw Exception("set menu using PopupMenu")
}
-
- animator.start()
}
- private fun animateIconTint() {
- val animator = ValueAnimator.ofObject(ArgbEvaluator(), itemIconTint, itemIconTintActive)
- animator.duration = itemAnimDuration
- animator.addUpdateListener {
- currentIconTint = it.animatedValue as Int
+ /**
+ * Created by Vladislav Perevedentsev on 29.07.2020.
+ *
+ * Just call [SmoothBottomBar.setOnItemSelectedListener] to override [onItemSelectedListener]
+ *
+ * @sample
+ * setOnItemSelectedListener { position ->
+ * //TODO: Something
+ * }
+ */
+ fun setOnItemSelectedListener(listener: (position: Int) -> Unit) {
+ onItemSelectedListener = object : OnItemSelectedListener {
+ override fun onItemSelect(pos: Int): Boolean {
+ listener.invoke(pos)
+ return true
+ }
}
+ }
- animator.start()
+ /**
+ * Created by Vladislav Perevedentsev on 29.07.2020.
+ *
+ * Just call [SmoothBottomBar.setOnItemReselectedListener] to override [onItemReselectedListener]
+ *
+ * @sample
+ * setOnItemReselectedListener { position ->
+ * //TODO: Something
+ * }
+ */
+ fun setOnItemReselectedListener(listener: (position: Int) -> Unit) {
+ onItemReselectedListener = object : OnItemReselectedListener {
+ override fun onItemReselect(pos: Int) {
+ listener.invoke(pos)
+ }
+ }
}
- private fun d2p(dp: Float): Float {
- return resources.displayMetrics.densityDpi.toFloat() / 160.toFloat() * dp
+ companion object {
+ private const val INVALID_RES = -1
+ private const val DEFAULT_INDICATOR_COLOR = "#2DFFFFFF"
+ private const val DEFAULT_TINT = "#C8FFFFFF"
+ private const val DEFAULT_ICON_BG_PADDING = 6f
+
+ // corner flags
+ private const val NO_CORNERS = 0;
+ private const val TOP_LEFT_CORNER = 1;
+ private const val TOP_RIGHT_CORNER = 2;
+ private const val BOTTOM_RIGHT_CORNER = 4;
+ private const val BOTTOM_LEFT_CORNER = 8;
+ private const val ALL_CORNERS = 15;
+
+ private const val DEFAULT_SIDE_MARGIN = 10f
+ private const val DEFAULT_ITEM_PADDING = 10f
+ private const val DEFAULT_ITEM_SPACING = 8f
+ private const val DEFAULT_ANIM_DURATION = 200L
+ private const val DEFAULT_ICON_SIZE = 18F
+ private const val DEFAULT_ICON_MARGIN = 4F
+ private const val DEFAULT_TEXT_SIZE = 11F
+ private const val DEFAULT_CORNER_RADIUS = 20F
+ private const val DEFAULT_BAR_CORNER_RADIUS = 0F
+ private const val DEFAULT_BAR_CORNERS = TOP_LEFT_CORNER or TOP_RIGHT_CORNER
+
+ private const val OPAQUE = 255
+ private const val TRANSPARENT = 0
}
-}
\ No newline at end of file
+}
diff --git a/lib/src/main/java/me/ibrahimsn/lib/ext/ContextExt.kt b/lib/src/main/java/me/ibrahimsn/lib/ext/ContextExt.kt
new file mode 100644
index 0000000..5dd6535
--- /dev/null
+++ b/lib/src/main/java/me/ibrahimsn/lib/ext/ContextExt.kt
@@ -0,0 +1,8 @@
+package me.ibrahimsn.lib.ext
+
+import android.content.Context
+import kotlin.math.roundToInt
+
+internal fun Context.d2p(dp: Float): Float {
+ return (dp * resources.displayMetrics.density).roundToInt().toFloat()
+}
diff --git a/lib/src/main/res/values/attrs.xml b/lib/src/main/res/values/attrs.xml
index 876f981..29bb1da 100644
--- a/lib/src/main/res/values/attrs.xml
+++ b/lib/src/main/res/values/attrs.xml
@@ -1,20 +1,36 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
\ No newline at end of file
+
+
diff --git a/lib/src/test/java/me/ibrahimsn/lib/ExampleUnitTest.kt b/lib/src/test/java/me/ibrahimsn/lib/ExampleUnitTest.kt
deleted file mode 100644
index c72a784..0000000
--- a/lib/src/test/java/me/ibrahimsn/lib/ExampleUnitTest.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package me.ibrahimsn.lib
-
-import org.junit.Test
-
-import org.junit.Assert.*
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}